为什么我要使用自动实现而不是封装?

Why would I use auto-implementation over encapsulation?

private int someInt;

public int GetSomeInt()
{
    return someInt;
}

我什么时候会在下面的代码上使用上面的代码?

public int SomeInt { get; set; }

有人告诉我 总是 封装 所有 变量而不是将它们声明为 public,并自动执行似乎就是这么做的。

声明字段时,这不会使封装的目的无效吗public?

以下代码是合成糖之类的东西。

public int MyValue { get; set; }

如果您查看之后生成的 IL (MSIL) 代码,您就会明白编译器实际在做什么。

.class public auto ansi beforefieldinit ConsoleApplication3.Sample
    extends [mscorlib]System.Object
{
    // Fields
    .field private int32 '<MyValue>k__BackingField'
    .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = (
        01 00 00 00
    )
    .custom instance void [mscorlib]System.Diagnostics.DebuggerBrowsableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggerBrowsableState) = (
        01 00 00 00 00 00 00 00
    )

    // Methods
    .method public hidebysig specialname 
        instance int32 get_MyValue () cil managed 
    {
        .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = (
            01 00 00 00
        )
        // Method begins at RVA 0x205c
        // Code size 7 (0x7)
        .maxstack 8

        IL_0000: ldarg.0
        IL_0001: ldfld int32 ConsoleApplication3.Sample::'<MyValue>k__BackingField'
        IL_0006: ret
    } // end of method Sample::get_MyValue

    .method public hidebysig specialname 
        instance void set_MyValue (
            int32 'value'
        ) cil managed 
    {
        .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = (
            01 00 00 00
        )
        // Method begins at RVA 0x2064
        // Code size 8 (0x8)
        .maxstack 8

        IL_0000: ldarg.0
        IL_0001: ldarg.1
        IL_0002: stfld int32 ConsoleApplication3.Sample::'<MyValue>k__BackingField'
        IL_0007: ret
    } // end of method Sample::set_MyValue

    .method public hidebysig specialname rtspecialname 
        instance void .ctor () cil managed 
    {
        // Method begins at RVA 0x2053
        // Code size 8 (0x8)
        .maxstack 8

        IL_0000: ldarg.0
        IL_0001: call instance void [mscorlib]System.Object::.ctor()
        IL_0006: nop
        IL_0007: ret
    } // end of method Sample::.ctor

    // Properties
    .property instance int32 MyValue()
    {
        .get instance int32 ConsoleApplication3.Sample::get_MyValue()
        .set instance void ConsoleApplication3.Sample::set_MyValue(int32)
    }

} // end of class ConsoleApplication3.Sample

在上面的代码编译器自动生成私有字段。

.field private int32 '<MyValue>k__BackingField'

所以字段仍然是私有的,属性 是 public。您还可以为 get 和 set 指定访问修饰符以控制 属性 访问级别。

自动实现只是封装字段的语法糖,适用于除了设置或检索字段值之外不需要其他逻辑的情况。它不会取代封装,只是为了节省时间和击键次数。您自己的代码无法访问自动实现的 属性 的支持字段——可见的只有 属性。此 属性 及其访问器可以具有字段可以具有的任何相同访问修饰符。

一个更准确的自动实现的等同于你拥有的东西,有一个私有支持字段,包含一个私有 setter:

public int SomeInt { get; private set; }

When would I use the above code over the below code?

你什么时候按括号付钱的? :-)

记住密码

public int SomeInt { get; set; }

是 shorthand 相当于

private int someInt;

public int SomeInt
{
   get { return someInt; }
   set { someInt = value; }
}

因此,您可以想象在 GetSomeInt 方法中放入的任何逻辑也可以在 'getter'(或 'setter')中放入 SomeInt 属性.

在可能的情况下,您应该使用 public int SomeInt { get; set; } 语法,因为它会立即提醒 reader 您所拥有的是一个简单的 属性,无需任何进一步的逻辑即可设置或访问被理解。

如果获取或设置逻辑更复杂,则可以使用更长形式的 属性 定义。

尽管我对括号的评论很滑稽,Property Design 的框架设计指南建议

If a getter can throw an exception, it should probably be redesigned to be a method. Notice that this rule does not apply to indexers, where we do expect exceptions as a result of validating the arguments.

因此,这将是您可以实施 GetSomeInt 而不是 SomeInt 属性 getter.

的情况的一个示例