开发者

understanding private setters

I don't understand the need of having private setters开发者_StackOverflow中文版 which started with C# 2.

Having a setter method for me is letting the user to set some variables in that class. In doing so, we will not expose the variables directly to the users. Instead we let them do it through this public setter method.

This for me is using "encapsulation". There are some arguments out there which claim that private setters will let you apply encapsulation.

Am I not using encapsulation by using public setter methods? Why do we need private setters?

What is the difference between immutable class and a class with private setters?


Logically.

The presence of a private setter is because you can use auto property:

public int MyProperty { get; set; }

What would you do if you want to make it readonly?

public int MyProperty { get; }

Oh crap!! I can't access it from my own class; I should create it like a normal property:

private int myProperty;
public int MyProperty { get { return myProperty; } }

Hmm... but I lost the "Auto Property" feature...

public int MyProperty { get; private set; }

AHHH.. that is better!!


A private setter is useful if you have a read only property and don't want to explicitly declare the backing variable.

So:

public int MyProperty
{
    get; private set;
}

is the same as:

private int myProperty;
public int MyProperty
{
    get { return myProperty; }
}

For non auto implemented properties it gives you a consistent way of setting the property from within your class so that if you need validation etc. you only have it one place.

To answer your final question the MSDN has this to say on private setters:

However, for small classes or structs that just encapsulate a set of values (data) and have little or no behaviors, it is recommended to make the objects immutable by declaring the set accessor as private.

From the MSDN page on Auto Implemented properties


With the introduction of C# 6.0 and the syntax for Auto-Property Initializers, private setters are no longer needed for properties that are only set upon initialization, either inline or within the constructor.

These new syntaxes now compile:

Inline initialized property

public class MyClass1 {
  public string MyProperty { get; } = "Aloha!"
}

Constructor initialized property

public class MyClass2 {
  public string MyProperty { get; }

  public MyClass2(string myProperty) {
    MyProperty = myProperty;
  }
}


It's rather simple. Private setters allow you to create read-only public or protected properties.

That's it. That's the only reason.

Yes, you can create a read-only property by only specifying the getter, but with auto-implmeneted properties you are required to specify both get and set, so if you want an auto-implemented property to be read-only, you must use private setters. There is no other way to do it.

It's true that Private setters were not created specificlly for auto-implemented read-only properties, but their use is a bit more esoteric for other reasons, largely centering around read-only properties and the use of reflection and serialization.


I don't understand the need of having private setters which started with C# 2.

For example, the invoice class allows the user to add or remove items from the Items property but it does not allow the user from changing the Items reference (ie, the user cannot assign Items property to another item list object instance).


public class Item
{
  public string item_code;
  public int qty;

  public Item(string i, int q)
  {
    this.item_code = i;
    this.qty = q;
  }
}

public class Invoice
{
  public List Items { get; private set; }

  public Invoice()
  {
    this.Items = new List();
  }
}

public class TestInvoice
{
  public void Test()
  {
    Invoice inv = new Invoice();
    inv.Items.Add(new Item("apple", 10));

    List my_items = new List();
    my_items.Add(new Item("apple", 10));

    inv.Items = my_items;   // compilation error here.
  }
}


Say for instance, you do not store the actual variable through the property or use the value to calculate something.

In such case you can either create a method to do your calculation

private void Calculate(int value)
{
 //...
}

Or you can do so using

public int MyProperty {get; private set;}

In those cases I would recommend to use the later, as properties refactor each member element intact.

Other than that, if even say you map the property with a Variable. In such a case, within your code you want to write like this :

public int myprop;
public int MyProperty {get { return myprop;}}

... ...

this.myprop = 30;

... ...
if(this.MyProperty > 5)
   this.myprop = 40;

The code above looks horrible as the programmer need always cautious to use MyProperty for Get and myprop for Set.

Rether for consistency you can use a Private setter which makes the Propoerty readonly outside while you can use its setter inside in your code.


I think a few folks have danced around this, but for me, the value of private setters is that you can encapsulate the behavior of a property, even within a class. As abhishek noted, if you want to fire a property changed event every time a property changes, but you don't want a property to be read/write to the public, then you either must use a private setter, or you must raise the event anywhere you modify the backing field. The latter is error prone because you might forget. Relatedly, if updating a property value results in some calculation being performed or another field being modified, or a lazy initialization of something, then you will also want to wrap that up in the private setter rather than having to remember to do it everywhere you make use of the backing field.


Yes, you are using encapsulation by using properties, but there are more nuances to encapsulation than just taking control over how properties are read and written. Denying a property to be set from outside the class can be useful both for robustness and performance.

An immutable class is a class that doesn't change once it's created, so private setters (or no setters at all) is needed to protect the properties.

Private setters came into more frequent use with the property shorthand that was instroduced in C# 3. In C# 2 the setter was often just omitted, and the private data accessed directly when set.

This property:

public int Size { get; private set; }

is the same as:

private int _size;
public int Size {
  get { return _size; }
  private set { _size = value; }
}

except, the name of the backing variable is internally created by the compiler, so you can't access it directly.

With the shorthand property the private setter is needed to create a read-only property, as you can't access the backing variable directly.


Encapsulation means that the the state of an object only happens through a defined interface, and because of this the class can make sure that this state is always valid and in keeping with the purpose of the class.

In some cases therefore, it's perfectly in keeping with the principle of encapsulation to just expose a field publicly - all possible values for the field are valid with all other possible values of all other fields, and therefore the programmer can actively decide to allow the field to be manipulated freely by outside code.

These cases are though mostly restricted to classes that are mostly "plain old data". They also aren't very interesting in this regard, so enough about them.

In other cases, in other languages, one would have a getter and setter method, something like int getId() to obtain a value and void setId(int val) to update it.

Properties let us use the same syntax for reading and writing through such methods as we would use to read and write a field. This is a good syntactic sugar, though not vital.

(Actually, due to the way that reflection works and cases such as DataBinder.Eval it can be handy to have a property even when a field would work fine, but that's another matter).

Up until private setters being introduced (actually, what changed with C# 2 is the syntax for having a private setter and a public or protected getter in the same block), we could have a private method to do the work of the private setter, so private setters aren't really necessary. They're handy though, so while just syntactic sugar, they're pretty useful.

Encapsulation is a matter not of whether your setters (or getters) are public, private, protected or internal, but a matter of whether they are appropriate. Start with a default of every field being private (and for that matter readonly) and then as necessary add members (whether properties or methods) that alter those fields, and ensure that the object remains valid as they change. This ensures that a class' invariant is kept, which means the rules describing the valid set of states it can be in are never broken (constructors also help by making sure it starts in such a valid state).

As for your last question, to be immutable means that a class has no public, protected or internal setters and no public, protected or internal methods that change any fields. There are degrees of this, in C# there are three degrees possible:

  1. All of a class' instance field's are readonly, hence even private code can't alter it. It is guaranteed to be immutable (anything that tries to change it won't compile) and possibly optimisations can be done on the back of this.

  2. A class is immutable from the outside because no public member changes anything, but not guaranteed by use of readonly to not be changed from the inside.

  3. A class is immutable as seen from the outside, though some state is change as an implementation detail. E.g. a field could be memoised, and hence while from the outside an attempt to get it just retrieves the same value, the first such attempt actually calculates it and then stores it for retrieval on subsequent attempts.


You need a private setter, if you want to support the following scenario (not only for this, but this should point out one good reason): You have a Property that is readonly in your class, i.e. only the class itself is allowed to change it, but it may change it after constructing the instance. For bindings you would then need to fire a PropertyChanged-event, preferrably this should be done in the (private) property setter. Actually, you could just fire the PropertyChanged-event from somewhere else in the class, but using the private setter for this is "good citizenship", because you do not distribute your property-change-triggers all over your class but keep it at the property, where it belongs.


I don't understand the need of having private setters which started with C# 2.

Use case example:

I have an instance of an application object 'UserInfo' that contains a property SessionTokenIDV1 that I don't wish to expose to consumers of my class.

I also need the ability to set that value from my class.

My solution was to encapsulate the property as shown and make the setter private so that I can set the value of the session token without allowing instantiating code to also set it (or even see it in my case)

public class UserInfo
{
   public String SessionTokenIDV1 { get; set; }

}


public class Example
{
  // Private vars
  private UserInfo _userInfo = new UserInfo();

  public string SessionValidV1
  {
    get { return ((_userInfo.SessionTokenIDV1 != null) && (_userInfo.SessionTokenIDV1.Length > 0)) ? "set" : "unset"; }
    private set { _userInfo.SessionTokenIDV1 = value; }
  }
}

Edit: Fixed Code Tag Edit: Example had errors which have been corrected


Despite the easy an clean way to write both, readonly, auto and private setters are things totally different.

Readonly properties are simply a fast and clean way to declare constants/statics in code:

   //constants
   public const int Constant = 50;
   public readonly int ReadOnly = 50;
   public int ConstantMethod() 
   {
       return 50;
   }

And for statics:

   public static readonly int Value = 50;
   public static int ValueMethod()
   {
       return 50;
   }

Any of them is the same thing, works the same way, except for readonly, that you can initialize in constructor. Even so, that´s a matter of how you like to code, changes nothing the results.

Remembering that static readonly is for types that don´t have literals, for methods inside classes or structs. Remembering also that new invokes the constructor of a class/struct.

Auto is the placeholder of:

    private int field;
    public int Property 
    {
        get
        {
            return field;
        }
         
        set
        {
            field = value;
        }
     }

     //In the auto property case, the "field" field is supressed, but it´s still 
     //there. 
       public int Property {get; set;}

So, private setters comes in auto properties, in any of this examples above. The keyword to considerate is private.

private, internal, protected and public are access keywords. So, if you declare:

    public int Property { get; private set; }

You just are saying that you want that the "set" part of Property can be changed only for the class itself.

    public int Property { get; protected set; }

Say that the "set" part of Property can be changed only by the class itself or for nested class of the base class. Also:

     private int Property { get; set; }
     public int Property {private get; private set; }

Both are the same. This is because the modifier that goes with the Property itself reflects in both "get" and "set" parts.


Credits to https://www.dotnetperls.com/property.

private setters are same as read-only fields. They can only be set in constructor. If you try to set from outside you get compile time error.

public class MyClass
{
    public MyClass()
    {
        // Set the private property.
        this.Name = "Sample Name from Inside";
    }
     public MyClass(string name)
    {
        // Set the private property.
        this.Name = name;
    }
    string _name;
    public string Name
    {
        get
        {
            return this._name;
        }
        private set
        {
            // Can only be called in this class.
            this._name = value;
        }
    }
}

class Program
{
    static void Main()
    {
        MyClass mc = new MyClass();
        Console.WriteLine(mc.name);

        MyClass mc2 = new MyClass("Sample Name from Outside");
        Console.WriteLine(mc2.name);
    }
}

Please see below screen shot when I tried to set it from outside of the class.

understanding private setters

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜