2

If I have a need for simple, private fields, is there any reason I shouldn't just make it a convention to use private, auto-implemented properties instead?

For instance, I could do this:

private MyClass _foo;

or I could do this:

private MyClass Foo { get; set; }

It seems like the only time I need actual fields is when I'm doing something like lazy loading:

private MyClass Foo
{
    get
    {
        if (_foo == null) _foo = new MyClass();
        return _foo;
    }
}
  • How about internal data integrity? Where do the rules for that go in your design? – Andy Oct 6 '15 at 16:04
  • @DavidPacker -- can you please elaborate? – rory.ap Oct 6 '15 at 16:05
  • 1
    @DavidPacker -- Are you talking about validation? If validation is required, then that would be elsewhere, of course. I wouldn't typically put that in a property anyway, but would separate that into a validation method that is called from the property body, in which case I couldn't use an auto-implemented property of the kind I'm referring to in my question. – rory.ap Oct 6 '15 at 16:10
  • If you are using auto implemented properties, then there's absolutely no difference except for the fact that properties end up polluting the resulting IL with useless getters and setters. – Matias Cicero Oct 6 '15 at 17:44
  • As an aside, if you're doing lazy-loading, you should use Lazy<T> rather than if(x == null) x = new T();. It clarifies in the type that the field is lazy and provides better thread safety. – Dan Lyons Oct 7 '15 at 17:35
3

The two features of fields that I feel you might run into more commonly that you would lose by converting them to properties are the following:

  1. You can't modify members of a property value if it's a value type.

    // Rectangle is a value type:
    struct Rectangle { int X, Y, Width, Height; }
    
    Rectangle rect;
    Rectangle RectProperty { get; set; }
    
    void Test()
    {
        // This works with a field:
        rect.X = 45;
    
        // but fails with a property:
        RectProperty.X = 45; // compiler error
    
        // The only way to update a value-type property 
        // is to construct & assign a completely new value:
        RectProperty = new Rectangle(45, RectProperty.Y, RectProperty.Width, RectProperty.Height);
    }
    
  2. You can't pass a property as an out or ref parameter

    int field;
    int SomeProperty { get; set; }
    
    void Test()
    {
        // Works with a field:
        int.TryParse("some text", out field); 
    
        // but fails with a property:
        int.TryParse("some text", out SomeProperty); // compiler error.
    
        // you need to create temporary storage instead:
        int x;
        if (int.TryParse("some text", out x)) { SomeProperty = x; }
    }
    

If neither of these is an issue for you, then you probably won't notice the difference. There are of course other differences if you're reflecting over your type, or using libraries that reflect over your type and expect things to be properties or fields, etc.

  • 1
    Neither of these should be an issue for anyone as they are both code smells. – David Arno Oct 7 '15 at 8:42
  • @DavidArno -- Indeed that seems to further bolster the claim that using properties in the way I'm proposing is better... – rory.ap Oct 7 '15 at 13:25
  • @roryap, maybe I'm misunderstanding you, but I feel I should clarify my comment. out and ref both break the single responsibility principle and thus their use is a code smell. Further, structs should be immutable and even badly written ones like Rectangle should be treated thus. However, both of these bad practices should be avoided as a matter of good practice. Enforcing them via properties is effectively a syntactic salt solution. – David Arno Oct 7 '15 at 13:48
  • 1
    @DavidArno -- Sorry for the confusion. I was agreeing with your point that these are both code smells, and I was saying therefore [given that your point is valid] wouldn't that bolster my claim... – rory.ap Oct 7 '15 at 13:51
  • Using out or ref aren't necessarily code smells. Note that I'm talking about using library methods and not writing your own methods. TryParse methods and Interlocked methods are prime examples of places where you would do this legitimately. – Erik Oct 8 '15 at 0:47
1

When dealing with public properties, the common reason given for doing

public MyClass Foo { get; set; }

rather than

public MyClass _foo;

is that the latter respects the open/closed principle better: if you later need to add guards/lazy loading etc to _foo, the latter requires a change to the API.

With private fields/properties though, this doesn't apply. The internal workings of your class are completely open to rewriting at all times. So if you do

private MyClass Foo { get; set; }

rather than

private MyClass _foo;

then, as Mati Cicero says in his comment, you simply end up polluting your resultant IL with pointless getter and setter methods.

Taking your lazy loading example, you can create a very succinct helper property to lazy setup _foo using C# 6:

private MyClass _foo;
private MyClass Foo => _foo ?? (_foo = new MyClass());

The compactness of the syntax, and thus the lack of noise, arguable makes the benefits of lazy-loading via a property better than using a helper method. As demonstrated by the length of your own example, using a helper method was arguably was a better solution prior to v6.

The other possible use with C# 6 is in replacing:

private readonly MyClass _bar = new MyClass();

with

private MyClass Bar { get; } = new MyClass();

Whether the latter is more readable is highly questionable though; arguably it both creates a pointless getter and makes the intention of the code less clear.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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