我应该使用字段还是 属性?
Should I use a field or a property?
首先,我看过asking for the difference between fields and properties这个问题,知道它的用途
现在回答我的问题,我想创建一个 属性,我确信 get 和 set 都是空的,所以我做了 get; set;
。一切都很好。但现在我意识到我刚刚创建了一个大写名称的 public 字段,它在所有方面都是相同的。
甚至不能说它被使用以便未来的代码不依赖于实现的论点,因为我可以简单地将其设为 属性 并实现 getter 或 setter. 字段的语义和 属性 在其定义的 class 之外是相同的。
所以我的问题是,当 属性 只使用 get;set;
时,我应该使用字段还是 属性?
所以这个:
public IEnumerable<string> Products;
在所有方面都与此相同:
public IEnumerable<string> Products { get; set; }
should I use a field or a property when a property would simply use get;set;?
使用 属性... 出于以下实际原因,以及出于哲学原因,属性公开状态 API,而字段公开状态实现细节。
The semantics of a field and a property are identical outside the class it is defined in.
这不是真的。
- 差异通过反射可见,这通常非常重要。例如,许多绑定框架不会使用字段,只会使用属性。
- 您可以通过 ref 传递可变字段,但不能通过 属性 - 因此将字段更改为 属性 会破坏源兼容性。 (当
Products
变为 属性 时,使用 SomeMethod(ref x.Products)
的代码将失效。)
- 将字段更改为 属性 也会破坏 binary 兼容性,因此如果程序集 X 是针对程序集 Y v1.0 构建的,并且您将字段更改为属性 对于程序集 Y v1.1,则需要重建程序集 X 否则将无法正确执行
- 如果你有一个可变值类型(请不要这样做)然后当
Location
是一个字段时写 foo.Location.X = 10
是有效的(因为 x.Location
被归类为一个变量)而当 Location
是 属性 时则不是(因为表达式 x.Location
被归类为值)。如果你有一个方法(在你的邪恶可变类型中)改为改变值,那么 foo.Location.DoSomething()
将在两种情况下编译,但有不同的效果。全家同乐。
最好使用 auto-属性 语法,因为它会创建一个带有私有支持字段的 read/write 属性,从而允许您更改实现(从私有标量字段到字典条目或具有其他自定义逻辑的另一个后端),从而从其实现中释放 "class's interface"(与 interface
不同)。
请注意,对于集合成员属性,建议将其设置器设为私有,如下所示:
public IEnumerable<String> Products { get; private set;}
...这样只有包含 class 才能改变它。
另一种选择是 private readonly
字段,在 C# 6 中,您可以将自动实现的属性与 readonly
后备字段一起使用,如下所示:
public IEnumerable<String> Products { get; } = SomeSource.GetProducts();
视情况而定。我更喜欢在字段上使用 属性。您提到 public IEnumerable<string> Products;
和 public IEnumerable<string> Products { get; set; }
相同,但实际上它们不是。在编译期间,属性 将被转换为两种方法(即 get_Products() 和 set_Products())。
属性 的优点是允许您在分配和返回数据之前指定自定义代码,这对于该字段是不可能的。检查下面的例子
public IEnumerable<string> Products
{
get
{
if(DateTime.Now.Date > Convert.ToDateTime("01-01-2016"))
{
//Return future product
return new List<string>();
}
else
{
// return current products
return new List<string>() { "testing" };
}
}
set
{
if (DateTime.Now.Date > Convert.ToDateTime("01-01-2016"))
{
//ignore assign product
Products = new List<string>();
}
else
{
// add assign product
Products = value;
}
}
}
首先,我看过asking for the difference between fields and properties这个问题,知道它的用途
现在回答我的问题,我想创建一个 属性,我确信 get 和 set 都是空的,所以我做了 get; set;
。一切都很好。但现在我意识到我刚刚创建了一个大写名称的 public 字段,它在所有方面都是相同的。
甚至不能说它被使用以便未来的代码不依赖于实现的论点,因为我可以简单地将其设为 属性 并实现 getter 或 setter. 字段的语义和 属性 在其定义的 class 之外是相同的。
所以我的问题是,当 属性 只使用 get;set;
时,我应该使用字段还是 属性?
所以这个:
public IEnumerable<string> Products;
在所有方面都与此相同:
public IEnumerable<string> Products { get; set; }
should I use a field or a property when a property would simply use get;set;?
使用 属性... 出于以下实际原因,以及出于哲学原因,属性公开状态 API,而字段公开状态实现细节。
The semantics of a field and a property are identical outside the class it is defined in.
这不是真的。
- 差异通过反射可见,这通常非常重要。例如,许多绑定框架不会使用字段,只会使用属性。
- 您可以通过 ref 传递可变字段,但不能通过 属性 - 因此将字段更改为 属性 会破坏源兼容性。 (当
Products
变为 属性 时,使用SomeMethod(ref x.Products)
的代码将失效。) - 将字段更改为 属性 也会破坏 binary 兼容性,因此如果程序集 X 是针对程序集 Y v1.0 构建的,并且您将字段更改为属性 对于程序集 Y v1.1,则需要重建程序集 X 否则将无法正确执行
- 如果你有一个可变值类型(请不要这样做)然后当
Location
是一个字段时写foo.Location.X = 10
是有效的(因为x.Location
被归类为一个变量)而当Location
是 属性 时则不是(因为表达式x.Location
被归类为值)。如果你有一个方法(在你的邪恶可变类型中)改为改变值,那么foo.Location.DoSomething()
将在两种情况下编译,但有不同的效果。全家同乐。
最好使用 auto-属性 语法,因为它会创建一个带有私有支持字段的 read/write 属性,从而允许您更改实现(从私有标量字段到字典条目或具有其他自定义逻辑的另一个后端),从而从其实现中释放 "class's interface"(与 interface
不同)。
请注意,对于集合成员属性,建议将其设置器设为私有,如下所示:
public IEnumerable<String> Products { get; private set;}
...这样只有包含 class 才能改变它。
另一种选择是 private readonly
字段,在 C# 6 中,您可以将自动实现的属性与 readonly
后备字段一起使用,如下所示:
public IEnumerable<String> Products { get; } = SomeSource.GetProducts();
视情况而定。我更喜欢在字段上使用 属性。您提到 public IEnumerable<string> Products;
和 public IEnumerable<string> Products { get; set; }
相同,但实际上它们不是。在编译期间,属性 将被转换为两种方法(即 get_Products() 和 set_Products())。
属性 的优点是允许您在分配和返回数据之前指定自定义代码,这对于该字段是不可能的。检查下面的例子
public IEnumerable<string> Products
{
get
{
if(DateTime.Now.Date > Convert.ToDateTime("01-01-2016"))
{
//Return future product
return new List<string>();
}
else
{
// return current products
return new List<string>() { "testing" };
}
}
set
{
if (DateTime.Now.Date > Convert.ToDateTime("01-01-2016"))
{
//ignore assign product
Products = new List<string>();
}
else
{
// add assign product
Products = value;
}
}
}