1

I'm having a dilemma with Get-Only props vs readonly after we can assign Get-Only right away like this string X { get; } = "dd" . So the question is: Why do we ever want to favour using readonly field in a class after C# 6 instead of using Get-Only property?

We can do this:

EX 1.

private readonly IService _service;
public A(IService service)
{
    _service = service;
}

BUT we can also do this:

private IService _service { get; }
public A(IService service)
{
    _service = service;
}

Both scenarios can only be initialized in ctor and can be used only within a class.

We can do those (from ctor as well):

EX 2.

private string SomeString { get; } = "s";
private readonly string SomeString2 = "s";

I cannot inherit readonly field but I can inherit Get-Only prop, which might be confusing to distinguish from the inherited prop but only when you have a capital naming convention for private props, if you use _prop you are fine. So more flexibility here.

We can also have:

EX 3.

public readonly string Field;
public string Field2 { get; }

And those are working the same except for minor thing for dev awareness - he cannot tell on the spot if the Field2 was not inherited.

I used to write DTO's like this:

EX 4.

public class DTOProp
{
    public string Field1 { get; }
    public string Field2 { get; }
    public string Field3 { get; }

    public DTOProp(string field1, string field2, string field3)
        => (Field1, Field2, Field3) = (field1, field2, field3);
}

Currently like this

public record DTORec(string Field1, string Field2, string Field3);

But never seen like this:

public class DTORo
{
    public readonly string Field1;
    public readonly string Field2;
    public readonly string Field3;

    public DTORo(string field1, string field2, string field3)
        => (Field1, Field2, Field3) = (field1, field2, field3);
}

We can write the hypothesis for readonly fields that can look like that -

When You use C# 6+ You can safely replace readonly fields with Get-Only properties with no side effects

and it seems completely valid to me.

After we replace the readonly-ies we end up with a more predictable way of writing a code without losing the meaning of the code and well as changing the behaviour.

I understand that the backing field will be created and it might have some performance impact but to optimize the application to that point we will probably have 99% more important issues in other places. The only thing that might be an "issue" is the problem I mentioned in EX 3 but it probably evens out with time to respond to a PR comment "why not Get-Only prop here?".

PS. Tried to find a similar question. Didn't actually find the answer I was looking for

Pawel
  • 525
  • 3
  • 16
  • 2
    This seems like a redux of [the usual property vs field argument](https://stackoverflow.com/questions/295104/what-is-the-difference-between-a-field-and-a-property). The existence of a new shorthand for read only properties with initializers doesn’t change the recommended uses - it just makes it take one line where it used to take two. – Mitch Apr 14 '22 at 20:14
  • 1
    @Mitch: I think that the use cases for *private, read-only* fields/properties are sufficiently distinct from "regular" fields and properties that a separate question is justified. – Heinzi Apr 14 '22 at 20:17
  • 1
    A read-only, auto-implemented property is still a `readonly` field, but now you have to use a method (the `get` accessor method) to read it, so unless you can guarantee aggressive inlining will be respected, you're now calling a method to get the field value, even from within the class. It still does the job, but it's just not the same thing anymore. Your hypothesis suffers the can/should question. Yes, you can use read-only, auto-implemented properties, but should you? Probably not. – madreflection Apr 14 '22 at 20:30
  • @Heinzi - I disagree, but I’m not voting to close, just throwing my two cents out there. The normal advice about properties vs fields is about encapsulating logic - insulating consumers from changes in implementation. ”readonly” private props don’t give this benefit, add extra syntax, and are potentially performance impacting. – Mitch Apr 14 '22 at 20:31
  • As a side note, not all get-only properties are auto-implemented, so your post inadvertently is referring to a broader class of properties that don't fit into this mold. You should familiarize yourself better with these terms, and the underlying implementation details, before attempting to drive paradigm changes. – madreflection Apr 14 '22 at 20:31
  • @Mitch How can you change the Get-Only prop value after its initialized? You would have to change the actual logic. You cannot do this: `private string _name { get => M1(_name); } = "aa";` and you also cannot do this `private string _name2 { get => M1(_name2); }` when field is initialized in ctor. If you do this `private string _name3 { get => M1(SomeOtherField); }` you can as well just remove `readonly` if we are changing the actual logic – Pawel Apr 14 '22 at 20:58
  • @madreflection Sorry but not sure what you mean. I have both cases as examples for initialization - take a look at EX 1. and EX 2 and the question is about Get-Only and `readonly` (only those) – Pawel Apr 14 '22 at 21:18
  • 1
    Asking for list of use cases is generally off-topic on SO. In this case it looks like @Pawel you want to discuss coding style (whether private property used as backing filed for a public property is a good idea or not) which I believe is opinion-based (there is no strong reasons to pick one or another). – Alexei Levenkov Apr 14 '22 at 21:39
  • @AlexeiLevenkov The initial question "Why do we ever want to favour using readonly field in a class after C# 6 instead of using Get-Only property?" I didn't want it to be opinion based. The question might have been asked like "Why do we ever want to favour using IQuerable over IEnumerable?". Actually there are already two anwers, one is in short "Because you want to have encapsulated readonly ref field" which I think is a pretty good answer the current coding standards is also a pretty good answer since the intent of dev is also important. – Pawel Apr 14 '22 at 22:09
  • @Pawel, I don't understand the question "How can you change the Get-Only prop value after its initialized?" since the whole point of a `get`-only property is that you can't change the value. – Mitch Apr 15 '22 at 00:48
  • @Mitch I'm referring to encapsulation you mentioned "The normal advice about properties vs fields is about encapsulating logic - insulating consumers from changes in implementation". As far as I can see when you change the `readonly` to `get`-only you will have the same encapsulation. After the value is initialized we cannot really change the value same as with `readonly`. So actually I can't see the importance of the argument about adding extra "benefits" unless you change the actual behavior of code execution (like intermediate function for init in ctor). – Pawel Apr 15 '22 at 14:03
  • @Pawel, yeah. That’s what I’m saying. Fields are the canonical “default”, so why add the complexity (both syntactically and technically) when there is no benefit? The argument is that you should use a property to encapsulate logic, *and otherwise default to using a field*. – Mitch Apr 15 '22 at 17:32
  • @Mitch imo complexity has not been added, in fact, we are making the code more consistent since there will be props everywhere and currently there are mixtures of `readonly` and `get`-only all over the place. If someone from your team would create a DTO based on `readonly` (EX 4.) you would probably put a comment in PR since it's inconsistent with other DTOs (even though it reduces complexity). I believe this is the same case – Pawel Apr 15 '22 at 21:13
  • @Pawel, questions which are primarily opinion based are off topic for StackOverflow. It is an empirical statement that a property is more syntactically and technically complex than a field since it necessarily includes accessors. If you have specific circumstances that make it make sense, go for it. – Mitch Apr 15 '22 at 22:45
  • @Mitch Statement "When You use C# 6+ You can safely replace `readonly` fields with Get-Only properties with no side effects" Rikki Gibson response ~"you can't because of ref". Where is the opinion here? – Pawel Apr 15 '22 at 22:52
  • @Pawel, the question asked was “*why* use readonly fields [vs get-only properties]” - which is opinion based apart from truisms like “to encapsulate logic”. Asking “Are get-only properties and readonly fields interchangeable/indistinguishable” has factual answer (“no, they are not interchangeable - even though they may have similar uses”). – Mitch Apr 16 '22 at 01:27
  • @Mitch You are simplifying a bit here. The question asked was "Why do we **ever** want to favour using `readonly` field in a class after C# 6 instead of using Get-Only property?" - which has technical answer - and was followed with the hypotesis "When You use C# 6+ You can safely replace `readonly` fields with Get-Only properties with **no side effects**" - which also touches upon technical analysis (not speculations and opinions). I could also claim your question to be opinion-based because you can interchangeably use `readonly` and `get`-only in DTOs - it's a matter of opinion. – Pawel Apr 16 '22 at 01:48
  • Opinion based question would be "Why Windows Terminal looks better than Command-Line?" There is no technical answer for that. – Pawel Apr 16 '22 at 01:52

2 Answers2

3

You can take a ‘ref’ to a field, but you can’t for a property. If the field is of a struct type, this might be relevant to reduce copying.

Rikki Gibson
  • 4,136
  • 23
  • 34
  • Yup, that's a valid point. I actually never seen `ref readonly` field in production code though. – Pawel Apr 14 '22 at 20:15
3

When You use C# 6+ You can safely replace readonly fields with Get-Only properties with no side effects

From a technical point of view, you might be right (except for the ref edge case mentioned by Rikki in his answer).

However, after two decades of reading and writing C# code, I have the impression that, in idiomatic C#, it has become customary

  • to use fields for private data, unless you have a good reason to use a property instead, and
  • to use properties for public data, unless you have a good reason to use a field instead.

Thus, if you use a property for private data without an obvious reason, you make your code a bit harder to read for others, since you violate one of the unwritten conventions of the language. It's a "mental speed bump" when reading your code: People stop to wonder why you used a property, when a field would have served the same purpose.

Heinzi
  • 167,459
  • 57
  • 363
  • 519