了解私人定制者
我不明白需要有从C#2开始的私人设置器。
给我一个setter方法是让用户在这个类中设置一些variables。 这样做,我们不会将variables直接暴露给用户。 相反,我们让他们通过这个公开的setter方法来做到这一点。
这对我来说是使用“封装”。 有一些说法,声称私人定居者会让你申请封装。
我不使用公共setter方法封装? 为什么我们需要私人定制者?
不可变类与私有setter类有什么区别?
按道理。
私人setter的存在是因为你可以使用自动属性:
public int MyProperty { get; set; }
如果你想使它只读,你会怎么做?
public int MyProperty { get; }
哦,废话! 我无法从我自己的class级上访问它; 我应该创造它像一个正常的属性:
private int myProperty; public int MyProperty { get { return myProperty; } }
嗯…但我失去了“汽车物业”function…
public int MyProperty { get; private set; }
AHHH ..这是更好的!
如果您拥有只读属性并且不想显式声明备份variables,则私有设置器很有用。
所以:
public int MyProperty { get; private set; }
是相同的:
private int myProperty; public int MyProperty { get { return myProperty; } }
对于非自动实现的属性,它给你一个一致的方式来设置你的类内的属性,所以如果你需要validation等你只有一个地方。
为了回答你的最后一个问题,MSDN有这样的私人安装者的话:
但是,对于只是封装一组值(数据)并且行为很less或没有行为的小类或结构体,build议通过将set访问器声明为private来使对象不可变。
从Auto Implemented属性的MSDN页面
这很简单。 私人设置器允许您创build只读公共或受保护的属性。
而已。 这是唯一的原因。
是的,你可以通过只指定getter来创build一个只读属性,但是对于auto-implmeneted属性,你需要指定get和set,所以如果你希望自动实现的属性是只读的,你必须使用私人二传手。 没有其他办法可以做到这一点。
私人设置器并不是专门为自动实现的只读属性创build的,但是由于其他原因,它们的使用更加深奥,主要集中在只读属性和reflection和序列化的使用上。
通过引入C#6.0和Auto-Property Initializers的语法,对于只在初始化时设置的属性(内联或在构造函数中),不再需要私有setter。
现在编译这些新的语法:
内联初始化属性
public class MyClass1 { public string MyProperty { get; } = "Aloha!" }
构造函数初始化属性
public class MyClass2 { public string MyProperty { get; } public MyClass2(string myProperty) { MyProperty = myProperty; } }
我不明白需要有从C#2开始的私人设置器。
例如,发票类允许用户添加或删除项目属性中的项目,但不允许用户更改项目引用(即用户无法将项目属性分配给其他项目列表对象实例)。
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. } }
比如说,你不通过属性存储实际的variables,或者使用这个值来计算一些东西。
在这种情况下,您可以创build一个方法来进行计算
private void Calculate(int value) { //... }
或者你可以使用
public int MyProperty {get; private set;}
在这种情况下,我会build议使用后者,因为属性重构每个成员元素不变。
除此之外,如果甚至说你用variables映射属性。 在这种情况下,你想在你的代码中写下这样的内容:
public int myprop; public int MyProperty {get { return myprop;}} ... ... this.myprop = 30; ... ... if(this.MyProperty > 5) this.myprop = 40;
上面的代码看起来很糟糕,因为程序员需要谨慎使用MyProperty for Get和myprop for Set。
为了保持一致性,你可以使用一个私有的setter,这个私有的setter可以在外面使用它的setter,而你可以在你的代码中使用它的setter。
封装意味着一个对象的状态只能通过一个定义好的接口来实现,因此类可以确保这个状态总是有效的并且符合类的目的。
因此,在某些情况下,完全按照封装的原则公开地公开一个字段 – 该字段的所有可能的值对所有其他字段的所有其他可能值都是有效的,因此程序员可以主动决定允许该字段由外部代码自由操纵。
这些情况大多只限于那些大多是“普通的旧数据”的类。 在这方面他们也不是很有意思,对他们来说就够了。
在其他情况下,在其他语言中,可能会有一个getter和setter方法,类似于int getId()
来获取值,而void setId(int val)
来更新它。
属性让我们使用相同的语法来读写,通过我们用来读写字段的方法。 这是一个很好的语法糖,虽然不重要。
(实际上,由于reflection工作的方式和DataBinder.Eval
这样的情况,即使字段可以正常工作,也可以有一个属性,但这是另一回事)。
直到引入私有setter(实际上,用C#2改变的是在同一个块中拥有private setter和public或protected getter的语法),我们可以使用私有方法来完成私有setter的工作。私人定制者并不是真的有必要。 他们很方便,虽然只是语法糖,但它们非常有用。
封装不是你的制定者(或获得者)是公开的,私人的,保护的还是内部的,而是一个问题是否合适 。 开始默认每个字段是私有的(就此而言, readonly
),然后根据需要添加更改这些字段的成员(不pipe是属性还是方法), 并确保对象在更改时保持有效 。 这确保了一个类的不变性被保留下来,这意味着描述它的有效状态集合的规则永远不会被破坏(构造函数也会帮助确保它在这个有效的状态下启动)。
至于你的最后一个问题,不可变意味着一个阶级没有公共的,受保护的或内部的制定者,也没有任何改变任何领域的公共的,受保护的或内部的方法。 有这个程度,在C#中有三个可能的程度:
-
所有类的实例字段都是
readonly
,因此即使私有代码也不能改变它。 它保证是不可变的(任何试图改变它的东西都不会被编译),并且可以在这个后面进行优化。 -
一个类从外部是不可改变的,因为没有任何公共成员改变任何东西,但不能保证只使用
readonly
而不能从内部改变。 -
一个类从外部看是不可变的,尽pipe有些状态是作为实现细节而改变的。 例如,一个字段可能会被记忆,因此,从外部尝试获取它只是检索相同的值,第一个这样的尝试实际上计算它,然后存储它在随后的尝试检索。
我觉得有几个人围绕这一点跳舞,但对我来说,私人定制者的价值在于你可以封装一个属性的行为,甚至在一个类中。 正如阿布舍克所指出的,如果每次财产变动时,如果要发生财产变更的事件,但不希望财产被读/写给公众,那么您必须使用私人调解人,否则您必须提高事件在任何地方修改后台字段。 后者是容易出错的,因为你可能会忘记。 相关的,如果更新一个属性值会导致一些计算被执行,或者另一个字段被修改,或者一些懒惰的初始化,那么你也想把它包装在私有的setter中,而不是记得在你做的任何地方使用后台字段。
是的,您使用的是使用属性的封装,但封装的细微差别不仅仅在于如何控制属性的读写。 拒绝从课外设置的属性对于健壮性和性能都是有用的。
一个不可变的类是一个一旦创build就不会改变的类,所以需要私有的setter(或者根本不需要setter)来保护这些属性。
在C#3中引入的属性速记使私人定制者更频繁地使用。在C#2中,定位者往往只是被省略,并且在设置时直接访问私有数据。
这个性质:
public int Size { get; private set; }
是相同的:
private int _size; public int Size { get { return _size; } private set { _size = value; } }
除了支持variables的名称是由编译器内部创build的,所以你不能直接访问它。
由于不能直接访问后备variables,因此需要使用私有setter来创build只读属性。
我不明白需要有从C#2开始的私人设置器。
用例示例:
我有一个应用程序对象'UserInfo'
的实例,其中包含一个SessionTokenIDV1
属性,我不想公开给我的类的消费者。
我还需要能够从我的class级设置这个价值。
我的解决scheme是封装如下所示的属性,并使setter私有,以便我可以设置会话令牌的值,而不允许实例化代码也设置它(甚至在我的情况下看到它)
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; } } }
编辑:固定代码标签编辑:例如有错误已被纠正
你需要一个私有的setter,如果你想支持下面的场景(不仅是为了这个,但是这应该指出一个很好的理由):你有一个属性是只读的在你的类中,也就是说只有类本身被允许改变它,但它可能会改变它构造实例后。 对于绑定,你需要触发一个PropertyChanged事件,最好这应该在(private)属性设置器中完成。 实际上,你可以从类的其他地方开始PropertyChanged事件,但是使用私有setter来实现这个function是“良好的公民权”,因为你不会在你的课堂上分发你的property-change-triggers,而是把它留在财产,它属于哪里。