如何实现只读属性

我需要在我的types上实现只读属性。 此外,这个属性的值将在构造函数中设置,它不会被改变(我正在写一个暴露WPF自定义路由UI命令的类,但没关系)。

我看到两种方式来做到这一点:

  1. class MyClass { public readonly object MyProperty = new object(); } 
  2.  class MyClass { private readonly object my_property = new object(); public object MyProperty { get { return my_property; } } } 

由于所有这些FxCop的错误说,我不应该有公共成员variables,看来,第二个是正确的方法来做到这一点。 正确?

在这种情况下,获取唯一属性和只读成员之间是否有区别?

我会很感激任何意见/build议/等。

版本:
如果你只对源代码兼容性感兴趣,我认为它没有太大的区别。
使用属性对于二进制兼容性更好,因为您可以将其replace为具有setter的属性,而不会根据您的库破坏已编译的代码。

惯例:
你遵循这个惯例。 在这种情况下,两种可能性之间的差异相对较小,遵循公约更好。 一个可能会回来咬你的例子是基于reflection的代码。 它可能只接受属性而不接受字段,例如属性编辑器/查看器。

序列化
从字段到属性的更改可能会破坏很多序列化器。 而AFAIK XmlSerializer只能序列化公共属性而不是公共字段。

使用Autoproperty
另一个常见的变化是使用私有setter的自动属性。 虽然这是短暂的,财产并不强制只读。 所以我更喜欢其他的。

只读字段是自我logging
这个领域有一个优势:
它清楚地看到了公共接口,它实际上是不可变的(禁止reflection)。 而在属性的情况下,你只能看到不能改变它,所以你不得不参考文档或实现。

但说实话,我在应用程序代码中经常使用第一个,因为我很懒。 在图书馆,我通常更加彻底,遵循公约。

C#6.0添加了只读自动属性

 public object MyProperty { get; } 

因此,当您不需要支持较旧的编译器时,您可以拥有一个真正的只读属性,其代码与只读字段一样简洁。

第二种方法是首选。

 private readonly int MyVal = 5; public int MyProp { get { return MyVal;} } 

这将确保MyVal只能在初始化时分配(也可以在构造函数中设置)。

正如你所指出的 – 这样你就不会暴露一个内部成员,允许你在将来改变内部的实现。

通过引入C#6(在VS 2015中),现在get只有自动属性,其中隐式后台字段是readonly (即,值可以在构造函数中分配,但不在其他地方):

 public string Name { get; } public Customer(string name) // Constructor { Name = name; } private void SomeFunction() { Name = "Something Else"; // Compile-time error } 

你现在也可以初始化属性(有或没有setter)inline:

 public string Name { get; } = "Boris"; 

回过头来看这个问题,选项1的简洁性给了你选项2(公众成员是财产,而不是领域)的优点。

不幸的是,它不能提供公共接口层面的不可变性保证(就像@ CodesInChaos关于自我logging的观点),因为对于这个类的消费者来说,没有一个setter与一个私人setter是没有区别的。

你可以这样做:

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

我同意第二种方式是可取的。 这种偏好的唯一真正原因是.NET类没有公共字段的一般偏好。 但是,如果这个领域是只读的,我看不出有什么真正的反对意见,除了与其他财产不一致。 readonly字段和get-only属性之间的真正区别在于readonly字段提供了一个保证,它的值在对象的生命周期中不会改变,只有get的属性不会改变。

由于封装,第二种方法是优选的。 你当然可以将只读字段公开,但是这违背了C#习惯用法,在这种习惯用法中,通过属性而不是字段来访问数据。

其原因在于,该属性定义了一个公共接口,如果该属性的后续实现发生更改,则不会因为实现隐藏在接口后面而最终破坏其余的代码。