59

In what situation should I use a Private Set on a property versus making it a ReadOnly property? Take into consideration the two very simplistic examples below.

First example:

Public Class Person

    Private _name As String

    Public Property Name As String
        Get
            Return _name
        End Get
        Private Set(ByVal value As String)
            _name = value
        End Set
    End Property

    Public Sub WorkOnName()

        Dim txtInfo As TextInfo = _
            Threading.Thread.CurrentThread.CurrentCulture.TextInfo

        Me.Name = txtInfo.ToTitleCase(Me.Name)

    End Sub

End Class

// ----------

public class Person
{
    private string _name;
    public string Name
    {
        get { return _name; }
        private set { _name = value; }
    }

    public void WorkOnName()
    {
        TextInfo txtInfo = System.Threading.Thread.CurrentThread.CurrentCulture.TextInfo;
        this.Name = txtInfo.ToTitleCase(this.Name);
    }
}

Second example:

Public Class AnotherPerson

    Private _name As String

    Public ReadOnly Property Name As String
        Get
            Return _name
        End Get
    End Property

    Public Sub WorkOnName()

        Dim txtInfo As TextInfo = _
            Threading.Thread.CurrentThread.CurrentCulture.TextInfo

        _name = txtInfo.ToTitleCase(_name)

    End Sub

End Class

// ---------------

public class AnotherPerson
{
    private string _name;
    public string Name
    {
        get { return _name; }
    }

    public void WorkOnName()
    {
        TextInfo txtInfo = System.Threading.Thread.CurrentThread.CurrentCulture.TextInfo;
        _name = txtInfo.ToTitleCase(_name);
    }
}

They both yield the same results. Is this a situation where there's no right and wrong, and it's just a matter of preference?

1
  • public string Name { get; protected set; } through inheritance.
    – samus
    Commented Apr 2, 2018 at 16:21

7 Answers 7

50

There are a couple reasons to use private set.

1) If you are not using a backing field at all and want a read-only automatic property:

public string Name { get; private set; }   

public void WorkOnName()
{
    TextInfo txtInfo = Thread.CurrentThread.CurrentCulture.TextInfo;
    Name = txtInfo.ToTitleCase(Name);
}  

2) If you want to do extra work when you modify the variable inside your class and want to capture that in a single location:

private string _name = string.Empty;
public string Name 
{ 
    get { return _name; }
    private set 
    {
        TextInfo txtInfo = Thread.CurrentThread.CurrentCulture.TextInfo;
        _name = txtInfo.ToTitleCase(value);
    }
}

In general, though, it's a matter of personal preference. Far as I know, there are no performance reasons to use one over the other.

5
  • 2
    Just adding this because the question also has a vb.net tag, but in vb.net you need to specify a backer if you use private on either either get or set. So in vb.net it's actually less work to make the property readonly I think.
    – user643192
    Commented Feb 26, 2013 at 7:08
  • I never knew about that private set. :-) Commented Sep 12, 2014 at 16:27
  • 13
    An update for those reading this answer in 2016. C# 6.0 has introduced readonly auto-properties, which allow you to have a readonly property without a backing field: public string Name { get; }. If you don't want a mutable property, that's the preferred syntax now.
    – Alexey
    Commented Feb 22, 2016 at 14:04
  • 4
    One very good reason not to use private set is that it's not as immutable as we like to pretend it is. If you want to implement a truly immutable class, read only is a must.
    – RubberDuck
    Commented Jul 7, 2016 at 0:04
  • May be a performance reason to NOT use readonly. Seems to cause unnecessary copying of structs when accessing methods of a readonly struct field. codeblog.jonskeet.uk/2014/07/16/…
    – Triynko
    Commented Jul 31, 2019 at 21:52
38

Use private set when you want setter can't be accessed from outside.

Use readonly when you want to set the property only once. In the constructor or variable initializer.

TEST THIS:

void Main()
{
    Configuration config = new Configuration();
    config.ResetConfiguration();

    ConfigurationReadOnly configRO = new ConfigurationReadOnly();
    configRO.ResetConfiguration();
}

public class Configuration
{
    public Color BackgroundColor { get; private set; }
    public Color ForegroundColor { get; private set; }
    public String Text { get; private set; }

    public Configuration()
    {
        BackgroundColor = Color.Black;
        ForegroundColor = Color.White;
        Text = String.Empty;
    }

    public void ResetConfiguration()
    {
        BackgroundColor = Color.Black;
        ForegroundColor = Color.White;
        Text = String.Empty;
    }
}

public class ConfigurationReadOnly
{
    public readonly Color BackgroundColor;
    public readonly Color ForegroundColor;
    public readonly String Text;

    public ConfigurationReadOnly()
    {
        BackgroundColor = Color.Black;
        ForegroundColor = Color.White;
        Text = String.Empty;
    }

    public void ResetConfiguration()
    {
        BackgroundColor = Color.Black; // compile error: due to readonly keyword
        ForegroundColor = Color.White; // compile error: due to readonly keyword
        Text = String.Empty; // compile error: due to readonly keyword
    }
}
2
  • While I agree with your answer, your example could use some improvement. You may want to make a comment where the compiler error would occur. Commented Aug 4, 2014 at 18:19
  • NB The VB.NET syntax corresponding to the C# readonly keyword, is to apply ReadOnly to the field instead of to the property.
    – Zev Spitz
    Commented Jan 3, 2019 at 9:18
11

Might I suggest a third option?

public class Person
{
    public string Name { get; protected set; }

    public void SetName(string name)
    {
        TextInfo txtInfo = System.Threading.Thread.CurrentThread.CurrentCulture.TextInfo;
        this.Name = txtInfo.ToTitleCase(name);
    }
}

This makes the Name property effectively Read Only to all outside code and provides an explicit Set method. I prefer the explicit Set rather than simply using the set on the Name property because you are changing the value when setting it. Normally if you set a property value, you expect to get the same value back when you call the get later on, which would not happen if you did your ToTitleCase in the set.

However, as you said, there is no one right answer.

2
  • I believe 'private set' has special semantics in the compiler (not simply performing as a private accessor). Is this also the case with protected set? If not, where's the semantic equivalent to protected set if private set has special semantics? I haven't been able to find any documentation explaining this.
    – Sprague
    Commented Mar 31, 2012 at 9:30
  • 1
    +1 but I would call the method "Rename" instead of "SetName".
    – MattDavey
    Commented Oct 8, 2012 at 14:07
7

Starting in C# 6.0, getter-only auto properties have been added into the language. See here: https://github.com/dotnet/roslyn/wiki/New-Language-Features-in-C%23-6#getter-only-auto-properties.

Here's an example:

public class SomeClass
{
    public int GetOnlyInt { get; }

    public int GetOnlyIntWithInitializer { get; } = 25;

    public SomeClass(int getOnlyInt)
    {
        GetOnlyInt = getOnlyInt;
    }
}
6

Don't use the second example. The whole point of using a property - even if there is nothing going on beyond the getter getting and the setter setting - is to funnel all access through that getter and setter so that if you ever need to change behaviour in the future, it's all in one place.

Your second example abandons that in the case of setting the property. If you used that approach in a large, complex class, and later needed to change the behaviour of the property, you'd be in search-and-replace land, instead of making the change in one place - the private setter.

2

Whenever I've needed to change the access level of a setter, I've generally changed it to either Protected (only this class and derived classes can change the value) or Friend (only members of my assembly can change the value).

But using Private makes perfect sense when you want to do other tasks in the setter besides changing the backing value. As pointed out earlier, it's good design to not reference your backing values directly but instead only access them through their properties. That ensures that later changes you make to a property are applied internally as well as externally. And there's virtually no performance penalty to referencing a property vs its backing variable.

0

And there's virtually no performance penalty...

But to clarify, accessing a property is slower than accessing its backing variable. A property's getter and setter are methods that require a Call and a Return, whereas a property's backing variable is accessed directly.

That's why, in cases where a property's getter may be accessed many times within a block of code, the property's value is sometimes cached first (saved in a local variable) and the local variable used instead. Of course, that assumes the property can't be changed asynchronously while the block is executing.

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