C# in Depth

Cover of C# in Depth
Order now (3rd edition)

Why Properties Matter

In chapter 8, I blithely assume that readers regard using properties instead of fields as best practice. Eric suggested that I mention why it's good practice. I felt it didn't quite fit into the chapter, but it's something which comes up every so often in newsgroups and mailing lists, so I thought I'd turn it into an article.

What choices are we considering?

It's worth being clear that this article does not address the question of whether something should be a method or a property. Sometimes it's not a clear-cut decision, and a discussion of the merits each way would be interesting but distract from the purpose of this article.

The choice I'm talking about in this article is how you expose data: as a property or as a non-private field. It's as simple as that. My personal view is that almost no fields should ever be non-private. I'll make a small exception for static readonly fields such as string.Empty, but that's (nearly) all.

So, if you've got a non-private field, why should you make it private and expose a property instead? I've split my points into three categories: compatibility problems, practical benefits of using properties, and the more philosophical considerations. Although the philosophical aspects sound less important, in fact they're the ones which give me more cause for concern.

Compatibility issues

Often people say it's fine to use fields for simple data, and then change them to properties when you need to. But...

You lose binary compatibility

This one isn't much of an issue if you're working on a project which always ships all of its binaries in one go, or if your field is currently internal and you don't expose the internals to any other assemblies. However, if you're writing a class library which may need to be updated without recompiling the code which uses it, you should understand that changing a field into a property is a breaking change. This includes serialization, too.

You lose source compatibility

You can use a property everywhere you can use a field, right? Wrong. You can use a field for ref parameters, whereas you can't (in C# at least) use a property in the same way. There are other subtle areas where there's a difference between fields and properties. Admittedly some (most?) of these involve mutable structs - another design decision to be avoided in almost all situations - but changing a field to a property in some cases can change the behaviour of code without even generating a warning or error. Here's an example showing that, admittedly involving a mutable struct:

using System;

struct MutableStruct
{
    public int Value { get; set; }
    
    public void SetValue(int newValue)
    {
        Value = newValue;
    }
}

class MutableStructHolder
{
    public MutableStruct Field;
    public MutableStruct Property { get; set; }
}

class Test
{    
    static void Main(string[] args)
    {
        MutableStructHolder holder = new MutableStructHolder();
        // Affects the value of holder.Field
        holder.Field.SetValue(10);
        // Retrieves holder.Property as a copy and changes the copy
        holder.Property.SetValue(10);
        
        Console.WriteLine(holder.Field.Value);
        Console.WriteLine(holder.Property.Value);
    }
}

The results are different: 10 for the first line, showing that the call to holder.Field.SetValue changed the value within holder.Field; 0 for the second line, showing that the call to holder.Property.SetValue didn't change the value of holder.Property.

If the mutating lines were just holder.Field.Value=10 and holder.Property.Value=10 then the change from field to property would be a breaking one - the latter wouldn't compile, because the expression holder.Property isn't classified as a variable. That's nicer than silently changing behaviour, but it's still an unwelcome change!

You lose reflection compatibility

Most of the time we don't use reflection to access members we can already get at directly. However, if someone does, that code will break if it's expecting a field to be present and it's been turned into a property unexpectedly.

Practical benefits of properties

There are times when you could use non-private fields, because for whatever reason you don't care about the compatibility reasons above. However, there are still benefits to using properties even for trivial situations:

None of these are traditional "adding real logic" uses of properties, but all are tricky/impossible with plain fields. You could do this on an "as and when I need it" basis, but why not just be consistent to start with? It's even more of a no-brainer with the automatic properties of C# 3.

The philosophical reason for only exposing properties

For every type you write, you should consider its interface to the rest of the world (including classes within the same assembly). This is its description of what it makes available, its outward persona. Implementation shouldn't be part of that description, any more than it absolutely has to be. (That's why I prefer composition to inheritance, where the choice makes sense - inheritance generally exposes or limits possible implementations.)

A property communicates the idea of "I will make a value available to you, or accept a value from you." It's not an implementation concept, it's an interface concept. A field, on the other hand, communicates the implementation - it says "this type represents a value in this very specific way". There's no encapsulation, it's the bare storage format. This is part of the reason fields aren't part of interfaces - they don't belong there, as they talk about how something is achieved rather than what is achieved.

I quite agree that a lot of the time, fields could actually be used with no issues in the lifetime of the application. It's just not clear beforehand which those times are, and it still violates the design principle of not exposing implementation.

Truly exceptional cases

There are exceptions to every rule, of course. Rico Mariani is a very smart guy who knows performance inside out and certainly knows design principles too. In a blog post about graphics primitives he details why he wrote a mutable struct with a size larger than 16 bytes, which exposes its fields publicly - breaking three fairly strong design guidelines with a single type. Don't just use this example as a reason to expose fields publicly - at least, not unless the same justifications apply too. Experts get to break rules in a very few cases, because they know exactly what they're getting themselves into. Mere mortals like myself - and like most readers of this page, I suspect - should at least spend a sleepless night thinking about their reasons before breaking such guidelines.

It's interesting to note that one of Rico's reasons for exposing fields is actually the same as my reason for normally preferring properties above - it exposes the implementation. Just occasionally, you want to give callers the confidence that the implementation will remain in a particular way for ever and a day - and that was the case here. I can't say that I've ever had to give that kind of guarantee in any code I've written, but we know that situations vary a lot.

A separate exceptional case I occasionally have used is making fields internal within a private nested type. As the type is private, this means the fact that it's a field still won't be exposed to any types other than the one it's nested in - which effectively "owns" the code for the nested type anyway. With C# 3 I'll probably use automatic properties for these situations anyway from now on - it was only ever a matter of convenience.

Conclusion

In almost all cases, fields should be private. Not just non-public, but private. With automatic properties in C# 3, there's basically no cost in readability or the amount of code involved to use a property instead of a field. Very occasionally you might find a genuinely good reason, but think long and hard about it before committing to that choice, particularly if you'll be exposing it beyond internal access.