C#,不变性和公共只读字段
我曾经在很多地方看过,公开地公开这些内容并不是一个好主意,因为如果你以后想改变属性,你将不得不重新编译所有使用你的类的代码。
但是,在不可变类的情况下,我不明白为什么你需要改变属性 – 毕竟你不会为逻辑添加逻辑。
任何想法,我错过了什么?
差别的例子,对于那些比文本更容易阅读代码的人:)
//Immutable Tuple using public readonly fields public class Tuple<T1,T2> { public readonly T1 Item1; public readonly T2 Item2; public Tuple(T1 item1, T2 item2) { Item1 = item1; Item2 = item2; } } //Immutable Tuple using public properties and private readonly fields public class Tuple<T1,T2> { private readonly T1 _Item1; private readonly T2 _Item2; public Tuple(T1 item1, T2 item2) { _Item1 = item1; _Item2 = item2; } public T1 Item1 { get { return _Item1; } } public T2 Item2 { get { return _Item2; } } }
当然,你可以使用自动属性( public T1 Item1 { get; private set; }
),但这只能让你“同意不变性”,而不是“保证不变性”。
这是一个明显的遗漏,你不能写下类似的东西:
public T2 Item2 { get; readonly set; }
我甚至不确定readonly
是最好的单词,意思是“只能在构造函数中设置” ,但这就是我们所坚持的。
这实际上是很多人要求的function,所以我们希望它能在不久的将来推出一个假想的新版本的C#。
看到这个相关的问题 。
C#6.0现在支持自动属性初始值设定项。
自动属性初始值设定项允许直接在声明中分配属性。 对于只读属性,它负责所有必要的仪式,以确保该属性是不可变的。
您可以在构造函数中初始化只读属性或使用自动初始化程序
public class Customer { public Customer3(string firstName, string lastName) { FirstName = firstName; LastName = lastName; } public string FirstName { get; } public string LastName { get; } public string Company { get; } = "Microsoft"; } var customer = new Customer("Bill", "Gates");
你可以在这里阅读更多关于自动属性初始值设定项
将来你可能不需要添加任何逻辑给setter,但是你可能需要给getter添加逻辑。
这足以让我使用属性而不是暴露字段。
如果我感觉严谨,那么我会去完全不变(明确的readonly
暴露的领域,没有安装者)。 如果我感到懒惰,那么我可能会去“同意不变性”(暴露的获取者和私人设置者的自动属性)。
作为一个标准的做法,我只关注你的第二个例子,只使用“只读”的对象是公开的或容易被无意中篡改。 我正在使用“商定的不变性”模型构build插件框架。 显然,在商定的不变性下, readonly
保护被删除。
只有在极less数情况下,我才会公开,公开,内部或其他方面。 除非写出一个属性{get;}比我愿意付出更多的时间,否则它会感觉不对。
物业背后的想法是,即使你现在或以后不打算改变他们,你可能需要以一种不可思议的方式。 假设您需要更改吸气剂来进行某种计算或logging。 也许你需要添加exception处理。 很多潜在的原因。
还要考虑语义。 如果T1是一个值types而不是引用types,那么访问obj.Item1将在getter中返回_Item1的副本,而访问没有getter的Item1则不会检索副本。 这意味着虽然Item1可能在内部是不可变的,但是返回的值types对象不是。 我想不出为什么这会是一件好事,但这是一个区别。