如何实现只读属性
我需要在我的类型上实现一个只读属性。此外,此属性的值将在构造函数中设置,并且不会更改(我正在编写一个类,该类公开 WPF 的自定义路由 UI 命令,但这并不重要)。
我看到有两种方法可以做到这一点:
类 MyClass { 公共只读对象 MyProperty = new object(); }
类 MyClass { 私有只读对象 my_property = new object(); 公共对象 MyProperty { 获取 { 返回 my_property; } } }
所有这些 FxCop 错误都表明我不应该有公共成员变量,看来第二个是正确的方法。这是正确的吗?
在这种情况下,仅获取属性和只读成员之间有什么区别吗?
I need to implement a read only property on my type. Moreover the value of this property is going to be set in the constructor and it is not going to be changed (I am writing a class that exposes custom routed UI commands for WPF but it does not matter).
I see two ways to do it:
class MyClass { public readonly object MyProperty = new object(); }
class MyClass { private readonly object my_property = new object(); public object MyProperty { get { return my_property; } } }
With all these FxCop errors saying that I should not have public member variables, it seems that the second one is the right way to do it. Is this correct?
Is there any difference between a get only property and a read only member in this case?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
C# 6.0 添加了只读自动属性
因此,当您不需要支持较旧的编译器时,您可以拥有一个真正的只读属性,其代码与只读字段一样简洁。
版本控制:
我认为如果您只对源兼容性感兴趣,那没有太大区别。
使用属性对于二进制兼容性更好,因为您可以将其替换为具有设置器的属性,而不会根据您的库破坏已编译的代码。
约定:
你遵守惯例。在这种情况下,两种可能性之间的差异相对较小,遵循惯例更好。一种可能会给你带来麻烦的情况是基于反射的代码。它可能只接受属性而不接受字段,例如属性编辑器/查看器。
序列化
从字段更改为属性可能会破坏很多序列化器。而且 AFAIK
XmlSerializer
仅序列化公共属性,而不序列化公共字段。使用自动属性
另一种常见的变体是使用带有私有设置器的自动属性。虽然这很短并且是一个属性,但它并不强制只读性。所以我更喜欢其他的。
只读字段是自记录的
不过,该领域有一个优势:
公共接口一目了然,它实际上是不可变的(除非反射)。而对于属性,您只能看到您无法更改它,因此您必须参考文档或实现。
但说实话,由于我很懒,我在应用程序代码中经常使用第一个。在图书馆,我通常会更加彻底并遵循惯例。
C# 6.0 adds readonly auto properties
So when you don't need to support older compilers you can have a truly readonly property with code that's just as concise as a readonly field.
Versioning:
I think it doesn't make much difference if you are only interested in source compatibility.
Using a property is better for binary compatibility since you can replace it by a property which has a setter without breaking compiled code depending on your library.
Convention:
You are following the convention. In cases like this where the differences between the two possibilities are relatively minor following the convention is better. One case where it might come back to bite you is reflection based code. It might only accept properties and not fields, for example a property editor/viewer.
Serialization
Changing from field to property will probably break a lot of serializers. And AFAIK
XmlSerializer
does only serialize public properties and not public fields.Using an Autoproperty
Another common Variation is using an autoproperty with a private setter. While this is short and a property it doesn't enforce the readonlyness. So I prefer the other ones.
Readonly field is selfdocumenting
There is one advantage of the field though:
It makes it clear at a glance at the public interface that it's actually immutable (barring reflection). Whereas in case of a property you can only see that you cannot change it, so you'd have to refer to the documentation or implementation.
But to be honest I use the first one quite often in application code since I'm lazy. In libraries I'm typically more thorough and follow the convention.
第二种方式是首选。
这将确保
MyVal
只能在初始化时分配(也可以在构造函数中设置)。正如您所指出的 - 这样您就不会暴露内部成员,从而允许您将来更改内部实现。
The second way is the preferred option.
This will ensure that
MyVal
can only be assigned at initialization (it can also be set in a constructor).As you had noted - this way you are not exposing an internal member, allowing you to change the internal implementation in the future.
随着 C# 6(在 VS 2015 中)的引入,您现在可以拥有仅
get
自动属性,其中隐式支持字段为readonly
(即可以分配值在构造函数中,但不在其他地方):现在您还可以内联初始化属性(带或不带 setter):
回到问题,这为您提供了选项 2 的优点(公共成员是属性,而不是字段):选项 1 的简洁性。
不幸的是,它不能保证公共接口级别的不变性(如 @CodesInChaos 关于自我文档的观点),因为对于该类的使用者来说,没有 setter 与没有 setter 是没有区别的有一个私人二传手。
With the introduction of C# 6 (in VS 2015), you can now have
get
-only automatic properties, in which the implicit backing field isreadonly
(i.e. values can be assigned in the constructor but not elsewhere):And you can now also initialise properties (with or without a setter) inline:
Referring back to the question, this gives you the advantages of option 2 (public member is a property, not a field) with the brevity of option 1.
Unfortunately, it doesn't provide a guarantee of immutability at the level of the public interface (as in @CodesInChaos's point about self-documentation), because to a consumer of the class, having no setter is indistinguishable from having a private setter.
在 C# 9 中,Microsoft 引入了一种新方法,仅使用
init
访问器,如下所示:这样,您可以在初始化新对象时赋值:
但稍后,您无法更改它:
In C# 9, Microsoft introduced a new way to have properties set only on initialization using the
init
accessor, like so:This way, you can assign values when initializing a new object:
But later on, you cannot change it:
你可以这样做:
You can do this:
还有另一种方式(我最喜欢),从 C# 6 开始
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/properties#expression-body-definitions
yet another way (my favorite), starting with C# 6
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/properties#expression-body-definitions
我同意第二种方式更好。这种偏好的唯一真正原因是人们普遍偏好 .NET 类没有公共字段。但是,如果该字段是只读的,除了与其他属性缺乏一致性之外,我看不出还会有任何真正的反对意见。只读字段和仅获取属性之间的真正区别在于,只读字段保证其值在对象的生命周期内不会改变,而仅获取属性则不然。
I agree that the second way is preferable. The only real reason for that preference is the general preference that .NET classes not have public fields. However, if that field is readonly, I can't see how there would be any real objections other than a lack of consistency with other properties. The real difference between a readonly field and get-only property is that the readonly field provides a guarantee that its value will not change over the life of the object and a get-only property does not.
由于封装,第二种方法是优选的。您当然可以将只读字段设置为公共,但这违背了 C# 习惯用法,在 C# 习惯用法中,数据访问是通过属性而不是字段进行的。
其背后的原因是该属性定义了一个公共接口,如果该属性的支持实现发生更改,您最终不会破坏其余的代码,因为该实现隐藏在接口后面。
The second method is preferred because of the encapsulation. You can certainly have the readonly field be public, but that goes against C# idioms in which you have data access occur through properties and not fields.
The reasoning behind this is that the property defines a public interface and if the backing implementation to that property changes, you don't end up breaking the rest of the code because the implementation is hidden behind an interface.
试试这个:
Try this: