有没有琐碎的财产保存你的培根?

那里有很多建议你不应该公开地公开你的字段,而是使用普通的属性。 我一遍又一遍地看到它。

我理解这些论点,但在大多数情况下 , 我认为这不是一个好建议 。

有没有人有一个真正重要的时间的例子? 在写一个琐碎的财产时,将来会有一些重要的东西(或者当没有使用它时会让它们陷入真正的麻烦)?

编辑:DataBinding参数是正确的,但不是很有趣。 DataBinding代码中的一个错误是它不接受公共字段。 因此,我们必须编写属性来解决该bug,而不是因为属性是明智的类设计选择。

编辑:要清楚,我正在寻找现实世界的例子,而不是理论。 真正重要的时刻。

编辑:在setter上设置断点的能力似乎很有价值。 为调试器设计我的代码是不幸的:我宁愿调试器变得更聪明,但考虑到我们的调试器,我将采用这种能力。 好东西。

在不确定的未来可能很难使代码工作,但这不是懒惰的借口。 在字段上编码属性是惯例,它是务实的。 称之为防御性编程。

其他人也会抱怨速度问题,但是JIT’er足够聪明,能够像暴露公共场地一样快。 足够快,我永远不会注意到。

想到一些非平凡的事情

  1. 公共字段完全公开,您不能强制使用只读或只写语义
  2. 属性可以具有不同的getset setibility(例如public get,internal set)
  3. 您不能覆盖字段,但可以拥有虚拟属性。
  4. 你的class级无法控制公共领域
  5. 你的class级可以控制财产。 它可以将设置限制为允许的值范围,标记状态已更改,甚至延迟加载值。
  6. 反思语义不同。 公共领域不是财产。
  7. 没有数据绑定,正如其他人指出的那样。 (这只是你的一个错误。 – 我能理解为什么.net框架设计师不支持他们不赞成的模式。)
  8. 您不能在接口上放置字段,但可以在接口上放置属性。
  9. 您的房产甚至不需要存储数据。 您可以创建外观并分派到包含的对象。

您只需输入额外的13个字符即可。 这似乎不像是投机性的普遍性。 存在语义差异,如果没有别的,属性具有不同的语义含义,并且比公共字段更灵活。

  public string Name { get; set; } public string name; 

我记得有一次第一次使用.net时,我将几个类编码为只是字段,然后由于某种原因我需要将它们作为属性,并且当我第一次完成它时完全浪费时间时间。

那么你有什么理由遵守惯例呢? 为什么你觉得需要游泳上游? 没有这样做,它为你节省了什么?

我有一个简单的属性,在调试时保存了几次。 .Net不支持数据断点(读或写)的概念。 有时,在调试非常复杂的场景时,跟踪对特定属性的读/写非常重要。 这对于一个属性很容易,但是对于一个领域来说是不可

如果您不在生产环境中工作,那么为了调试,重构字段 – >属性很简单。 有时候你会遇到只能在生产环境中重现的错误,这些错误很难用新的二进制文件修补。 物业可以救你。

但这是一个相当有限的情况。

杰伊,我曾经想过同样的事情。 为什么要使用一个属性,如果它只是提供直接访问私人成员? 如果你能把它描述为一个自动配置,那么拥有一个属性而不是一个领域似乎有点愚蠢。 即使您需要更改实现,您也可以随后重构为不动产,任何相关代码仍可正常工作,对吧? 好吧,也许不是。

你看,我最近看到了关于琐碎属性的亮点,所以也许现在我可以帮你做同样的事情。

最终让我信服的是相当明显的一点(回想起来).Net中的属性只是getter和setter方法的语法糖,而这些方法与属性本身有不同的名称 。 同一个程序集中的代码仍然有效,因为无论如何都必须同时重新编译它。 但是,如果您将字段重构为属性,则链接到您的不同程序集中的任何代码都将失败 ,除非它同时针对您的新版本重新编译。 如果它是一个从一开始的财产,一切都还是不错的。

部分想法是,这些属性在将来可能不会是微不足道的 – 如果您将外部代码绑定到某个字段,然后想要将其包装在属性中,则所有相关代码都必须更改,并且您可能无法要做到这一点,特别是在你是一个控制设计师或有你无法控制的图书馆等的情况下。

更不用说某些.NET实践不允许您特别使用字段 – 数据绑定。

我相信还有其他好的理由。 为什么这对你很重要? 使用自动属性并完成它。 似乎不值得关注的事情……

我将用另一个问题回答你的问题:你是否真的从没有让所有类型和成员公开中受益? 我怀疑我没有通过这样做直接防止任何错误。 但是,我已经正确地封装了我的类型,只暴露了暴露的内容。 属性是相似的 – 好的设计比什么都重要。 我认为属性在概念上与字段不同; 它们是合同的一部分,而不是从根本上实施的一部分。 将它们视为属性而不是字段有助于我更清楚地思考我的设计,从而获得更好的代码。

哦,我偶尔也因为没有破坏源兼容性,能够设置断点,日志访问等而受益。

如果由属性访问器包装,则调试涉及字段的问题要容易得多。 在访问者中放置断点可以很快帮助找到重新入侵和其他可能无法捕获的问题。 通过通过访问器封送所有对该字段的访问,您可以确切地确定谁正在改变什么和何时。

在.NET中,根据我的理解,你不能将数据绑定到公共字段; 但只限于物业。 因此,如果您想进行数据绑定,则别无选择。

我曾经想要从项目的窗口中显示字段,这些字段允许程序的统计信息(TotalItems和SuccessfulItems)。

后来我决定在表单上显示统计信息,并且能够在设置器中添加一个调用,在属性更改时更新显示。

显然,如果您没有创建共享类库,并且您没有使用DataBinding,那么使用字段将不会给您带来任何问题。

但是如果你正在创建一个共享类库,那么除了遵循这些指导方针之外,你愚蠢的恕我直言,原因通常是三个:

  • 共享类库的使用者可能希望使用DataBinding。

  • 共享类的使用者可能需要二进制兼容性,如果从字段切换到属性,这是不可能的。

  • 最少意外的原则意味着您应该与其他共享类库(包括.NET Framework本身)保持一致。

恕我直言,没有像人们一直在呼唤他们那样的琐碎财产。 通过数据绑定工作等方式,微软暗示作为对象公共接口一部分的任何数据都应该是属性。 我认为它们并不仅仅意味着像它在其他语言中那样的惯例,其中属性语法更多地是关于约定和方便。

一个更有趣的问题可能是:“我应该何时使用公共领域而不是财产”,或“何时公共领域而非公共财产保存了你的培根?”

具有结构类型的字段允许直接访问其成员,而这些类型的属性不允许。 因此,如果Thing.BozPoint类型的字段,想要修改其X值的代码可以简单地说Thing.Boz.X += 5; ; 如果Thing.Boz是一个可变属性,则需要使用var tmp = Thing.Boz; tmp.X += 5; Thing.Boz = tmp; var tmp = Thing.Boz; tmp.X += 5; Thing.Boz = tmp; 。 用暴露的场地更清晰地写东西的能力通常( 但不总是 )是一种祝福。

如果Boz始终可以成为一个字段,那么直接修改其成员将比将其复制到临时变量更新,更快,更好,修改它并将其复制回来。 如果Boz的类型直接暴露其可变字段(如结构应该)而不是将它们包装在普通的包装器中,那么它们也可以使用诸如Interlocked方法之类的东西 – 这对于属性来说根本不可能。 以这种方式使用字段实际上只有一个缺点:如果需要用属性替换字段,那么依赖于字段的代码将会中断,并且可能很难修复。

简而言之,我认为如果一个人不关心能够交换不同版本的代码而不必重新编译任何消费者,使用属性而不是字段的最大效果是防止代码的消费者写代码,它将利用(并依赖于)结构类型的暴露字段的语义。

顺便提一下,暴露结构类型字段的替代方法是公开ActOnXXX方法。 例如:

 delegate void ActionByRef(ref T1 p1); delegate void ActionByRef(ref T1 p1, ref T2 p2); delegate void ActionByRef(ref T1 p1, ref T2 p2, ref T3 p3); // Method within the type that defines property `Boz` void ActOnBoz(ActionByRef proc, ref T1 p1) { proc(ref _Boz, ref p1); // _Boz is the private backing field } 

想要向Thing.Boz.X添加一些局部变量qThing.Boz.X可以调用Thing.ActOnBoz((ref Point pt, ref int x) => {pt.X += x;}, ref q); 并且直接在Thing._Boz上执行操作,即使该字段未公开。