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

时间:2008-10-15 17:05:42

标签: c# .net

有很多建议你不应该公开地公开你的字段,而是使用普通的属性。我看到了它&结束了。

我理解这些论点,但是I don't think it's good advice in most cases

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

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

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

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

11 个答案:

答案 0 :(得分:25)

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

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

想到一些非平凡的事情

  1. 公共字段完全公开,不能强制执行只读或只写语义
  2. 属性可以具有不同的getset辅助功能(例如,公共获取,内部设置)
  3. 您无法覆盖字段,但可以拥有虚拟属性。
  4. 您的班级无法控制公共领域
  5. 你的班级可以控制财产。它可以将设置限制为允许的值范围,标记状态已更改,甚至延迟加载值。
  6. 反射语义不同。公共领域不是财产。
  7. 没有数据绑定,正如其他人指出的那样。 (这只是你的一个错误。 - 我能理解为什么.net框架设计师不支持他们不赞成的模式。)
  8. 您不能在接口上放置字段,但可以在接口上放置属性。
  9. 您的财产甚至不需要存储数据。您可以创建一个外观并调度到包含的对象。
  10. 您只需输入额外的13个字符即可。这似乎不像是投机性的普遍性。存在语义差异,如果没有别的,属性具有不同的语义含义,并且比公共字段更灵活。

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

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

    那么遵循约定的原因是什么?为什么你觉得需要游泳上游?没有这样做,它为你节省了什么?

答案 1 :(得分:13)

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

如果您不在生产环境中工作,则重构字段很简单 - >属性用于调试。偶尔会遇到只能在生产环境中重现的错误,这些错误很难使用新的二进制文件进行修补。物业可以救你。

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

答案 2 :(得分:12)

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

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

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

答案 3 :(得分:10)

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

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

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

答案 4 :(得分:10)

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

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

答案 5 :(得分:3)

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

答案 6 :(得分:2)

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

答案 7 :(得分:1)

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

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

答案 8 :(得分:1)

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

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

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

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

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

答案 9 :(得分:0)

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

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

答案 10 :(得分:0)

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

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

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

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

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

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