4

I doubted to post this question to the general StackOverflow, but it is suggested to not post opinion-based questions and this might be one. And ofcourse, this is the software engineering department. Microsoft Docs only describes the how, not the why.

When should one use a:

  • property with a { get .... ; } and a backing field or;
  • a property with a { get .. ; private set .. ; }

Why would you want to show a user of your implementation then a property cannot be set with a literal assignement?

This might be the same topic of the choice between a property named Result with a calculation in the Get-method, or a plain method GetResult() returning thesame string.

1
  • 4
    Use a backing field when you want to do more than just get or set. Validation, for example. Commented Jul 16, 2020 at 15:02

4 Answers 4

1

If you are trying to keep your code as clean and abstract as possible, you will find that, most of the time, when you have a setter, you will want to define your own backing field (or you will wish you had, at some point).

  • Do you need to validate something in your setter? The only way you could do that is by having your own backing field, to make sure you are going to assign a valid value in there, before doing so.

  • Do you have, or are you planning to support, lazy initialization? Then you need a backing field to initialize manually on first acquisition (RAII?).

  • Are you going to use out-of-the-box serialization with the BinaryFormatter? If yes, remember that auto-properties entail a custom backing field that is "engraved" into the stored definitions. You cannot see the field, but it is right there and you cannot deserialize anymore without having the exact same auto-property. You cannot work around this either, because backing fields use some specialized characters you are not allowed to use (like <>).

To quote Telastyn: These days, the auto properties are preferred where possible. However, be extra careful not to interpret "where possible" as "as often as possible". The number of things you can do with auto-properties pales compared to what you can do with your own backing fields.

Why would you want to show a user of your implementation then a property cannot be set with a literal assignement?

Because you may not want to allow it, which is what encapsulation is all about. How would you go about a Count property of a collection? This is not something that would make sense to set externally, it is only determined by the internal workings of the class. You may +=1 it or -=1 it when adding/removing items manually, though, so that you know that it always represents what you want it to.

For the most part, the few use cases of auto-implemented properties I see anymore are for nullable dependencies that do not play important roles in the workings of your class. For example:


public class Collection<T>
{
    public Action<T> AddCallback {get; set;}

    public void Add(T item)
    {
        //Do add...
        
        //Raise the callback.
        AddCallback?.Invoke(item);
    }
}

Here, it doesn't really trouble your class whether the callback is null or not. Apart from that, only DTOs (Data-Transfer-Objects) have been another case where I have been generally using auto-properties, although that is, also, an arguable practice.

Bonus Reading

I sometimes see properties coming up as interface definitions. Keep in mind that properties are intended to express characteristics of an abstraction, not implementation details. It is very easy to abuse properties in an interface definition, as though you were defining fields. You don't want your implementation to leak through the abstraction. Or, to put it clearer, you don't want someone looking at your interface and knowing that you probably have a field somewhere, with the same name, to back your property. Fields are implementation details. Do not define properties on interfaces as field-wrappers of your implementations.

An example:

public interface IEnumerable<T>
{
    int Count { get; }
}

What is the meaning of Count here? I mean, I know that most people are probably intending to implement the interface through classes that generally have specified numbers of elements, but the interface is not expressing that, it is expressing the fact that your implementations can enumerate their elements, one by one. For all we know, the elements might be indefinite, or even infinite.

5
  • property with a { get .... ; } and a backing field
  • a property with a { get .. ; private set .. ; }

Note that your bullet points aren't quite correct. If you're using an auto property (i.e. not having an explicitly defined backing field), then the second bullet point's getter and setter should not have a body.

Once you explicitly define the body of the getters and setters, you're no longer using an auto property and you are required to either have a backing field or wire it to do whatever you need it to do.

Good practice dictates that properties should represent a stored (get) and storeable (set) state, so any getter or setter with an explicit body should refer to some kind of state, e.g. a backing field, property, external resource, ...


As the name implies, auto properties automatically use a backing field. get; and set; will be translated into the default get => _myGeneratedBackingField; and set => _myGeneratedBackingField = value; statements respectively.

I'm unsure whether private set; get translated to private set => _myGeneratedBackingField = value; or if the assignments to your property instead get rewired to the backing field. I would assume the former but either is possible. But it functionally does not make a difference in either case.

At runtime, it makes no difference whether you explicitly use a backing field or not. The only difference is during design time (i.e. while coding), where's it's either a matter of preference (how you want to use it) or fringe cases such as reflection which depend on the existence of a particular field in your class.

Auto properties are just syntactic sugar. Nice to work with, but wholly irrelevant post-compilation.

3

In general, you should only explicitly declare the backing field if there is some reason you need to. Things like playing nice with some existing base class, or working with reflection code that expects a field, or if you want readonly (set on initialization) behavior but don’t want to implement that by hand, or your setter is nontrivial.

The language didn’t have auto properties initially, so some of the very old documentation/code might only talk about backing fields. These days, the auto properties are preferred where possible.

1
  • 2
    Interfaces only focus on properties and methods, not fields. So an interface can never be the reason why you do/don't explicitly implement a backing field. Interfaces might be the reason why you wrap an existing field in a property, but that's not the question at hand.
    – Flater
    Commented Jul 16, 2020 at 15:10
0

This is a matter of preference. I do not like auto properties much, it leads to unnecessarily obscure code. I do use them sometimes but only for the most basic DTO-type of classes.

My problem with them is that the data members of a class are no longer guaranteed to be listed first. If you apply StyleCop you can be sure all data members will be the first thing you see when you study a class. If they are not there, they do not exist. What you will see before the first constructor is all of the class's data, period... Unless there are some of those hidden handy-dandy differently styled auto properties defined further down in the code. I hate that. When I encounter them I often just think "they (C# designers) should never have done this, people cannot handle the responsibility, this convenience is not worth the trouble".

1
  • Style Cop is not a law of nature. If you don't like that Style Cop orders the properties as they do, I'm sure you can change it.
    – nvoigt
    Commented Jul 19, 2020 at 8:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.