有啥理由使用自动实现的属性而不是手动实现的属性?
Posted
技术标签:
【中文标题】有啥理由使用自动实现的属性而不是手动实现的属性?【英文标题】:Any reason to use auto-implemented properties over manual implemented properties?有什么理由使用自动实现的属性而不是手动实现的属性? 【发布时间】:2011-12-28 08:27:38 【问题描述】:我了解 PROPERTIES 相对于 FIELDS 的优势,但我觉得使用 AUTO 实现的属性而不是 MANUAL 实现的属性并没有真正提供任何优势,只是让代码看起来更简洁一些。
我觉得使用起来更舒服:
private string _postalCode;
public string PostalCode
get return _postalCode;
set _postalCode = value;
代替:
public string PostalCode get; set;
主要是因为如果我想要执行任何类型的 get 和 set 自定义实现,我必须创建自己的属性,无论如何都要由私有字段支持。那么,为什么不从一开始就咬紧牙关,立即为所有属性赋予这种灵活性,以保持一致性呢?考虑到您在 Visual Studio 中所要做的就是单击您的私有字段名称,然后按 Ctrl+E,这真的不需要额外的一秒钟,您就完成了。如果我手动执行,那么我最终会出现不一致,其中有一些由私有字段支持的手动创建的公共属性,以及一些自动实现的属性。无论是全自动还是全手动,它始终保持一致,我感觉好多了。
这只是我吗?我错过了什么吗?我错了吗?我是否过于强调一致性?我总能找到关于 C# 特性的合法讨论,而且几乎所有事情都有利弊,但在这种情况下,我真的找不到任何人建议不要使用自动实现的属性。
【问题讨论】:
你说你现在也可以这样做——因为将来你might
必须这样做。为什么要浪费时间做一些容易出错的事情(无论如何,你最终可能会复制和粘贴),而你只能在需要时这样做?
谢谢罗伯。我的理由是,使用 Visual Studio,我可以通过一个额外的按键创建手动实现的属性,因此无需复制/粘贴。如果有一天我确实需要创建自己的实现,我不会在自动实现的属性和手动实现的属性之间产生分歧,它是 100% 一个或 100% 另一个。通过从一开始就完全手动,我可以随时创建自己的实现,而无需自动实现某些属性,并且某些属性是手动的。不过,我明白你的意思。
在这种情况下,我支持你坚持 100% 手动实现。在遇到许多手动 getter/setter 的错字错误后,我往往会产生偏见
在 VS 2010 中(至少),您可以输入 prop
并按 Tab。这会产生一个自动实现的属性。
C# 3.0 auto-properties - useful or not?的可能重复
【参考方案1】:
除了简洁之外,它并没有给你任何额外的东西。如果您更喜欢更冗长的语法,那么请务必使用它。
使用 auto props 的一个好处是,它可以潜在地使您免于犯愚蠢的编码错误,例如不小心将错误的私有变量分配给属性。相信我,我以前做过!
你关于自动道具不是很灵活的观点是一个很好的观点。您唯一的灵活性是使用private get
或private set
来限制范围。如果您的 getter 或 setter 对它们有任何复杂性,那么 auto props 不再是一个可行的选择。
【讨论】:
根据我的经验,公共属性使人们摆脱了 OOP 的思维方式。我现在正在进行的一个项目的对象有时仅初始化了一些属性,因此猜测该属性是否为空,并且代码库中有很多区域检查空值。我认为它们在某些情况下非常有用,在我强调的情况下,它们似乎是魔鬼。 @CodyEngel 不能保证通过访问器访问的对象也不为空。如果人们会编写带有属性的草率代码,那么他们也会编写没有属性的草率代码。【参考方案2】:有些人think that automatic properties can be somewhat evil 但除此之外他们只是语法糖。除了保存几行代码之外,您不会通过使用它们获得任何好处,并且您可能会为自己创造更多的工作(因为您想要进行一些检查或引发事件,所以以后必须手动实现它)。一致性在编程中非常有价值(恕我直言)。
【讨论】:
啊,所以在某个地方对此进行了讨论 :) 感谢您提供链接!【参考方案3】:我不了解其他人,但我倾向于停下来思考我应该为我的变量和函数命名,以便其他人能够理解我的代码。
所以当我使用 auto 实现的属性时,我只需暂停一次。
当我需要一个支持字段时我必须暂停两次,所以它会减慢开发速度:)
我的做法是:
-
一开始就将其设为私有变量
如果需要,将其更改为公开自动实现。
如果我需要获取或设置一些代码,请将其更改为支持字段。
如果一个类的不同属性以不同的方式暴露出来,这并没有错。
【讨论】:
【参考方案4】:您将失去控制的一件事是将支持字段指定为 NonSerialized 的能力,但在这种情况下为属性创建支持字段很容易。
忘记了:如果您或您使用的任何产品对成员(即 WCF)执行反射,那么您将看到损坏的支持字段名称,而不是您创建的“漂亮”支持字段。
如果您之前提供了对服务的访问权限,或者如果您在接收端反序列化为相同的类结构(即在 WCF 管道的两端使用相同的类),这可能非常重要。在这种情况下,您不一定能够反序列化,因为您可以保证支持字段名称是相同的,除非您与源代码共享相同的 DLL。
再澄清一点:假设您有一个 Web 服务,它通过 WCF 向您创建的 silverlight 客户端公开您的一些业务对象。为了重用您的业务逻辑,您的 Silverlight 客户端添加对您的业务对象的源代码的引用。如果您有自动实现的属性,则无法控制支持字段名称。由于 WCF 序列化成员而不是属性,因此您无法确定从 WCF 服务传输到 silverlight 的对象是否会正确反序列化,因为支持字段名称几乎肯定会不匹配。
【讨论】:
【参考方案5】:不保证自动实现的属性在构建之间保持相同的支持字段名称。因此,理论上在一个程序集版本中序列化一个对象,然后在另一个程序集中重新序列化同一对象可能会导致重大更改。
这极不太可能,但如果您试图保持将程序集“换出”新版本的能力,这是一个有效的问题。
通过使用手动实现的属性,您可以保证支持字段永远不会更改(除非您专门更改它)。
除了那个细微的差别之外,自动属性是一个普通属性,它使用支持字段自动实现。
【讨论】:
【参考方案6】:我看到使用自动属性的优势之一是;在调试应用程序时它不会进入不必要的 Get/Set 部分。我知道我们可以使用 Debugger Attributes 或 Step over 来避免相同的情况;但是,如果在大型应用程序上进行调试,大多数情况下会发生这种情况。
【讨论】:
【参考方案7】:我总能找到关于 C# 特性的合法讨论,而且几乎所有事情都有利弊,但在这种情况下,我真的找不到任何人建议不要使用自动实现的属性。
我在今天的代码审查中遇到了这个问题,当我询问我的同行时,我们也无法达成共识。我不喜欢模棱两可,我想知道至少一个能回答你问题的热门问题:
使用一种方式比另一种方式有性能提升或影响吗?就像要知道要舔多少次才能到达 Tootsie Roll Tootsie Pop 的中心,我决定“让我们找出答案”。
让我们首先实际做一个苹果与苹果的比较。
假设我们有两个类:
public class C
private int z;
public int Z
get return z;
public class Q
public int Z get;
第一个类是手动后备存储,第二个是自动编译器生成的版本。
让我们看看为每个生成的 IL。
一、手动后备存储版本:
// Fields
.field private int32 z
// Methods
.method public hidebysig specialname
instance int32 get_Z () cil managed
// Method begins at RVA 0x2050
// Code size 12 (0xc)
.maxstack 1
.locals init (
[0] int32
)
IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldfld int32 C::z
IL_0007: stloc.0
IL_0008: br.s IL_000a
IL_000a: ldloc.0
IL_000b: ret
// end of method C::get_Z
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
// Method begins at RVA 0x2068
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [System.Private.CoreLib]System.Object::.ctor()
IL_0006: nop
IL_0007: ret
// end of method C::.ctor
// Properties
.property instance int32 Z()
.get instance int32 C::get_Z()
现在让我们看看第二类的 IL:
// Fields
.field private initonly int32 '<Z>k__BackingField'
.custom instance void [System.Private.CoreLib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = (
01 00 00 00
)
.custom instance void [System.Private.CoreLib]System.Diagnostics.DebuggerBrowsableAttribute::.ctor(valuetype [System.Private.CoreLib]System.Diagnostics.DebuggerBrowsableState) = (
01 00 00 00 00 00 00 00
)
// Methods
.method public hidebysig specialname
instance int32 get_Z () cil managed
.custom instance void [System.Private.CoreLib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = (
01 00 00 00
)
// Method begins at RVA 0x2071
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldfld int32 Q::'<Z>k__BackingField'
IL_0006: ret
// end of method Q::get_Z
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
// Method begins at RVA 0x2068
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [System.Private.CoreLib]System.Object::.ctor()
IL_0006: nop
IL_0007: ret
// end of method Q::.ctor
// Properties
.property instance int32 Z()
.get instance int32 Q::get_Z()
忽略用于添加可调试属性的额外编译器生成代码,它不会添加明显的可执行代码,生成的代码似乎没有任何差异。
现在,您可能会争辩说您的问题没有得到解答,但请考虑...
如果您曾经编写过参与绑定的属性,例如:
private string name;
public string Name
get return name;
set SetProperty (ref name, value);
那么后备存储就是要走的路。
另一方面,使用 Visual Studio 编辑器中的“prop”
所以到最后,对于锤子来说,一切看起来都像钉子。不要当锤子。
【讨论】:
以上是关于有啥理由使用自动实现的属性而不是手动实现的属性?的主要内容,如果未能解决你的问题,请参考以下文章
Handsontable 怎么实现自动合并单元格,而不是用mergecells属性写死?