有没有理由在手动实现的属性上使用自动实现的属性?

时间:2011-11-14 03:22:05

标签: c# properties field encapsulation

我理解PROPERTIES优于FIELDS的优点,但我觉得使用自动实现的属性优于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#功能的合法讨论,并且几乎总是有利有弊,但在这种情况下,我真的找不到任何建议不使用自动实现属性的人。

7 个答案:

答案 0 :(得分:36)

除了简洁之外,它不会给你任何额外的东西。如果您更喜欢更详细的语法,那么请务必使用它。

使用自动道具的一个好处是它可以避免造成愚蠢的编码错误,例如意外地将错误的私有变量分配给属性。相信我,我以前做过!

关于汽车道具不是很灵活的一点是好的。您拥有的唯一灵活性是使用private getprivate set来限制范围。如果你的吸气剂或制定者有任何复杂性,那么汽车道具不再是一个可行的选择。

答案 1 :(得分:9)

不保证自动实现的属性在构建之间保持相同的支持字段名称。因此,理论上可能在一个版本的程序集中序列化一个对象,然后在另一个程序集中重新序列化该同一个对象可能会导致重大更改。

通过使用手动实现的属性,您可以保证后备字段永远不会更改(除非您专门更改它)。

除了那个微小的差异之外,自动属性是一个普通的属性,可以通过支持字段自动实现。

答案 2 :(得分:2)

有些人think that automatic properties can be somewhat evil但除此之外,他们只是语法糖。除了保存几行代码之外,你不会通过使用它们获得任何东西,并且你可以为自己创建更多的工作(之后必须手动实现它,因为你想做一些检查或引发一个事件)。一致性在编程(imho)中非常有价值。

答案 3 :(得分:2)

我不了解其他人,但我倾向于暂停一下,想一想我应该为变量函数命名,以便其他人可以理解我的代码。

因此,当我使用自动 - 已实现的属性时,我只需暂停一次

当我需要一个支持字段我必须暂停两次时,所以它会减慢开发速度:)

我这样做的方式是:

  1. 在开始时将其设为私有变量
  2. 如果需要,可以将其公开自动实施。
  3. 如果我在get或set中需要一些代码,请将其更改为支持字段。
  4. 如果类的不同属性以不同方式暴露,则没有错。

答案 4 :(得分:2)

您将无法控制的一件事是能够将支持字段指定为NonSerialized,但在这种情况下,为该属性创建支持字段非常容易。

忘记:如果您或您使用的任何产品对成员(即WCF)执行反射,那么您将看到错位的支持字段名称,而不是您创建的“漂亮”支持字段。

如果您之前提供了对服务的访问权限,或者您在接收端反序列化为相同的类结构(即在WCF管道的两端使用相同的类),这可能非常重要。在这种情况下,您不一定能够反序列化,因为您可以保证支持字段名称相同,除非您共享相同的DLL而不是源代码。

稍微澄清一下:假设您有一个Web服务,它通过WCF将您的一些业务对象暴露给您创建的Silverlight客户端。为了重用您的业务逻辑,您的Silverlight客户端会添加对业务对象的源代码的引用。如果您具有自动实现的属性,则无法控制支持字段名称。由于WCF序列化成员而不是属性,因此您无法确定从WCF服务转移到silverlight的对象是否会正确反序列化,因为支持字段名称几乎肯定会不匹配。

答案 5 :(得分:1)

我看到使用自动属性的一个优点是;在调试应用程序时,它不会进入不必要的Get / Set部分。我知道我们可以使用Debugger Attributes或Step over避免相同的事情;但是,如果在大型应用程序上进行调试,大多数情况都会发生。

答案 6 :(得分:0)

  

我总是可以找到有关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” 快捷方式生成自动属性非常方便,并且比 all 键入;)

因此,最后,对于锤子来说,一切看起来都像钉子。不要锤子。