省略 setter 的属性和带有私有 setter 的属性有什么区别?
public string Foo { get; private set; }
对
public string Foo { get; }
在 C# 6 中,
get;
只有属性只能从构造函数中设置。从其他地方来看,它是只读的。
带有
private set;
的属性可以从该类内的任何位置进行设置。
从类外部来看,如果使用以下语法,它不会改变任何内容:
public string Foo { get; }
但是你将无法在类中更新
Foo
,除了在构造函数中,为此,你需要私有设置器:
public string Foo { get; private set; }
不同之处在于,在第二种情况下,生成的代码将生成一个只读字段,并且显然该属性不会有 setter。
我们来做一个真实的例子:
public class Test
{
public Test(string name) { Name = name; }
public string Name { get; private set; }
}
编译器会这样编译:
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; }
}
}
如您所见,编译器已自动重写您的代码以拥有该属性的支持字段。字段名称将是那个神秘的名称,它是合法的 .NET,但不是 C#,这意味着您永远不能编写与此类自动生成的成员冲突的 C# 代码。
基本上,C# 中的自动属性只是带有支持字段的属性的语法糖,正在编译的实际属性仍然有一个支持字段,你只是不必显式地编写它。
如您所见,它还自动重写了构造函数以直接写入字段。请注意,这将在写入属性的类中的任何地方完成,因为无论如何都不可能有任何自定义代码介于两者之间。
现在让我们从属性中删除 setter 并看看会发生什么:
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; }
}
}
请注意,该字段现在是只读的,并且显然 setter 也已从该属性中消失。
因此,这实际上是现在创建具有 true 只读属性的简单类型的最佳方法,不仅属性本身不可写,而且支持字段也是只读的,这意味着您现在可以更好地轻松编写不可变类型 .
private
setter 是一种私有 set 方法,您只能在班级内部使用。
omissed 设置器使属性
readonly
。因此,您只能在构造函数中或通过静态初始化来设置此属性的值。
省略 setter 的属性在除类构造函数之外的所有位置都是只读的 - 包括在类内部。
具有私有 setter 的属性只能在外部读取(甚至对于子类),但在内部可写。
省略虚拟基类属性上的 setter 很有用,您希望派生子类重写这些属性,以便基类方法使用重写的properties 属性。该方法遵循 SOLID 中的开/闭原则。
public class BaseClass
{
public virtual int CookiesToEat { get; }
public void EatCookies()
{
Console.WriteLine($"Eating {CookiesToEat}");
}
}
public class ChildClass : BaseClass
{
get { return 5; }
}
BaseClass bc = new ChildClass();
bc.EatCookies();