Ever since the introduction of automatic properties in C#, I’ve been thinking about whether they should, in fact, be the only type of property that’s allowed. The reasoning behind the idea is very simple: if something magical is happening inside an auto-property (i.e., something beyond the typical store/load), then this something is a piece of domain logic or a non-functional requirement that has somehow crept into the entity/persistence layer. The typical result of this is code like the following:
public int Age {
get {
return age;
}
set {
// copious amounts of voodoo
if (age != value)
{
age = value;
NotifyPropertyChanged("Age");
}
}
}
This code is creepy for several reasons, the main being that end-users of this code won’t have a clue as to why the Age variable is behaving the way it does. Unless you document that it prevents self-assignment and notifies on change, that is. And even if you do that, would people then assume that
every property in the class behaves this way? You never know, really! You’ve just introduced lots of ambiguity that is unresolvable without either a good look at the code or, failing that, Reflector.
The above example is only the tip of the iceberg, because really, many people know about self-assignment checks and the
INotifyPropertyChanged interface. But what if we do even more hackery inside the property?
public int Age {
get {
return person.Age;
}
set {
// even more obscure voodoo
if (value >= 16)
person = new Adult(value);
else
person = new Minor(value);
}
}
More trouble! Now you have some
real voodoo happening inside the property. What if someone else decides to use the
person field without knowledge of what your
Age variable does? And what if
every property in this class needs to be done this way, but developers forget about it? They are doomed!
My take on making properties is to simply write the following:
public int Age { get; private set; }
That’s right – I make
Age pseudo-immutable, i.e., only assignable from within the class. That way, we don’t get into a situation where people haphazardly assign the value from several different threads. Of course, we also lose all the interesting stuff like self-assignment checks or change notification, but we can get them back – all we have to do is sprinkle some AOP on top of the class, and we’re good to go. For example, we can declaratively turn every property into a WPF-style dependency property, all without having to use the
propdp snippet and having extra
static XxxProperty fields in our code.
In fact, there are several
more things you can do with properties. First, you can use fields instead! After all, PostSharp (if that’s what you’re using) doesn’t care what to rewrite, and making a field is easier—but you do lose declarative immutability. What I mean is, you can just write the following:
public int Age;
You might have FxCop complain about a public field, but feel free to ignore it. Public fields are perfectly okay in the general case too, of course, but that’s another story.