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.