60

What is the difference between a property with a omitted setter and a property with a private setter?

public string Foo { get; private set; }

vs

public string Foo { get; }
Fred
  • 12,086
  • 7
  • 60
  • 83
  • 7
    Simple: a property with an omitted setter **does not have a setter**. You cannot reassign the property outside of the property declaration or a constructor. – BoltClock Apr 22 '16 at 11:19
  • 3
    duplicate alert :http://stackoverflow.com/questions/3847832/understanding-private-setters, http://stackoverflow.com/questions/4948816/getters-setters-and-properties-best-practices-java-vs-c-sharp – Tushar Gupta Apr 22 '16 at 11:20
  • @TusharGupta this one is tagged C#-6.0 – Thomas Ayoub Apr 22 '16 at 11:23
  • 1
    The chosen duplicate actually tells what the intended goal for the new syntax is, and though it contains both old text and new post-c#-6 text, it still answers the question, true immutability and readonly backing fields. – Lasse V. Karlsen Apr 22 '16 at 11:32

5 Answers5

77

In C# 6, get; only properties are only settable from the constructor. From everywhere else, it is read-only.

A property with a private set; can be set from everywhere inside that class.

Patrick Hofman
  • 153,850
  • 22
  • 249
  • 325
  • I see. I wonder why the functionality exists to have omitted setter. What would be the reason to declare a property only settable by the constructor but by methods inside the class? – Fred Apr 22 '16 at 11:40
  • To prevent setting that property by mistake from somewhere inside that method? – Patrick Hofman Apr 22 '16 at 11:41
  • 1
    You can **update** the property elsewhere in the class, you just can't **reassign** it. For example, if the property is a List you can call Clear() and Add() anywhere in the class even if no setter is declared. – kilgoretrout Jun 18 '18 at 21:58
  • @Fred because sometimes you don't want a property reference to change after it has been initially set in the constructor. You can do this with private data members as well with the `readonly` keyword: `private readonly string _name;` is the private analog to `public string Name { get; }`. (Btw: `public readonly Name { get; }` is redundant and not even allowed by the compiler.) – JohnB Aug 30 '20 at 16:56
12

From outside the class, it won't change anything if you use this syntax:

public string Foo { get; }

But you won't be able to update Foo within the class, except in the constructor, to do so, you'll need the private setter:

public string Foo { get; private set; }
Patrick Hofman
  • 153,850
  • 22
  • 249
  • 325
Thomas Ayoub
  • 29,063
  • 15
  • 95
  • 142
10

The difference is that the generated code will produce a readonly field in the second case, and obviously the property won't have a setter.

Let's do a real example:

public class Test
{
    public Test(string name) { Name = name; }
    public string Name { get; private set; }
}

The compiler will compile this like this:

public class Test
{
    private string <Name>k__BackingField;
    public Test(string name)
    {
        <Name>k__BackingField = name;
    }
    public string Name
    {
        get { return <Name>k__BackingField; }
        private set { <Name>k__BackingField = value; }
    }
}

As you can see the compiler has automagically rewritten your code to have a backing field for the property. The field name will be that cryptic name, which is legal .NET but not C# which means you can never write C# code that will conflict with such an automatically generated member.

Basically, automatic properties in C# is just syntactic sugar for a property with a backing field, the actual property being compiled still have a backing field, you just don't have to write it explicitly.

As you can see it also automatically rewrote the constructor to write directly to the field. Note that this will be done everywhere inside this class where the property is written to, since there is no chance for any custom code to be inbetween anyway.

Now let's remove the setter from the property and see what happens:

public class Test
{
    private readonly string <Name>k__BackingField;
    public Test(string name)
    {
        <Name>k__BackingField = name;
    }
    public string Name
    {
        get { return <Name>k__BackingField; }
    }
}

Notice that the field is now readonly, and again, obviously the setter has gone from the property as well.

So this is actually the best way now to create simple types with true readonly properties, not only is the property itself not writable, but the backing field is also readonly meaning you're now better equipped to easily write immutable types.

Community
  • 1
  • 1
Lasse V. Karlsen
  • 380,855
  • 102
  • 628
  • 825
  • Interesting, I guess that this also applies to static read-only properties (i.e. when it only declares an auto-getter) – Matías Fidemraizer Apr 22 '16 at 11:23
  • Yes, `static` doesn't matter in this regard – Lasse V. Karlsen Apr 22 '16 at 11:24
  • I didn't try to see what was happening with this case (either instance or private properties with just a `get;`). Thus, I won't manually declare more `readonly` fields ;P (unless I would need to don't encapsulate them, but accessing class fields without encapsulation is still a bad coding practice). – Matías Fidemraizer Apr 22 '16 at 11:27
4

The private setter is - well - a private set method you can use from inside your class only.

The omitted setter makes the property readonly. So you can only set the value of this property in your constructor(s) or via a static initialization.

René Vogt
  • 43,056
  • 14
  • 77
  • 99
3

A property with an omitted setter is read only everywhere except the class constructor - including inside the class.

A property with a private setter is read only externally (even to subclasses), but writeable internally.

ChrisF
  • 134,786
  • 31
  • 255
  • 325