【问题标题】:C# autoproperty vs normal fields [duplicate]C#自动属性与普通字段[重复]
【发布时间】:2013-03-11 03:59:30
【问题描述】:

在这个例子中 Foo.Something 和 Bar.Something 之间有什么有效的区别吗?

class Foo
{
    public string Something;
}

class Bar
{
    public string Something{get; set;}
}

class Program
{
    static void Main(string[] args)
    {
        var MyFoo = new Foo();
        MyFoo.Something = "Hello: foo";
        System.Console.WriteLine(MyFoo.Something);

        var MyBar = new Bar();
        MyBar.Something = "Hello: bar";
        System.Console.WriteLine(MyBar.Something);
        System.Console.ReadLine();
    }
}

AFAIK 他们的行为完全相同。如果他们这样做,为什么不使用 Foo 中的普通字段? 在 java 中,我们使用 setter 来强制执行新的不变量而不破坏代码和 getter 以返回安全数据,但在 c# 中,您始终可以将 Foo 重写为:

class Foo
{
    private string _Something;
    public string Something
    {
        get { 
            //logic
            return _Something; 
            }
        set { 
            //check new invariant
            _Something = value; 
            }
    }
}

而且旧代码不会被破坏。

【问题讨论】:

    标签: c# automatic-properties


    【解决方案1】:

    AFAIK 他们的行为完全一样。

    不,他们没有。

    • 字段不能用于数据绑定(至少在某些绑定实现中)
    • 您可以稍后为属性添加更多逻辑,而不会破坏源代码或二进制兼容性
    • 属性不能通过引用传递
    • 您不能将初始化程序添加到自动实现的属性中
    • 它们在反射方面显然会有所不同
    • 从哲学上讲,属性在逻辑上是 API 的一部分,而字段是实现细节

    在 c# 中,您总是可以将 Foo 重写为:[...]

    如果你不关心二进制或源代码兼容性,你可以,是的。在某些情况下,这真的不是问题 - 在其他情况下,这是非常非常大的问题。为什么不选择从一开始就公开你的 API 而不是你的实现细节呢?这不像在你的代码中添加{ get; set; } 会增加很多混乱......

    更多吐槽,请看我的article on this

    【讨论】:

    • 并且自动属性不能有(相当于)字段初始化器。例如,如果您最初想要Something = "initial",则必须使用该属性使您的实例构造函数显式并在该构造函数的主体中写入赋值(或所有构造函数,除非它们使用: this(...) 语法相互“链接”) .
    • Jon Skeet 提出一个问题,4 人赞成。
    • @JeppeStigNielsen:没错,没错。
    • @EaterOfCorpses 这在很大程度上与他无关,因为无论如何他已经远远超过了当天的代表上限。
    【解决方案2】:

    Foo.Something 是一个字段,Bar.Something 是一个自动实现的属性。这是一个巨大的差异。

    您可以像访问字段一样访问属性,但在访问属性时会在内部调用 set/get 方法。

    所以当您说myBar.Something = "asdf" 时,C# 编译器会将其转换为对 setter 方法的调用:myBar.set_Something("asdf")。 setter 和 getter 方法会自动为您生成,以及实际值的支持字段。

    通过将 Foo.Something 更改为具有 get 和 set 方法的属性,您破坏了二进制兼容性,这意味着您必须重新编译所有使用 Foo.Something 的程序集,而它仍然是一个字段。

    【讨论】:

      【解决方案3】:

      属性的 getter 和 setter(包括自动的)具有方法调用成本。应避免使用公共字段,以保持访问干净。

      【讨论】:

      • 你:应该避免公共字段 我猜公共readonly字段可以吗? BCL 使用它们。当然,这与原始问题无关。
      • @JeppeStigNielsen 我想是的。
      • @JeppeStigNielsen:BCL 很少使用只读的 instance 字段。常量(即使是非常量常量,如果你明白我的意思的话)是另一回事。
      • @JonSkeet 我猜你是对的。例如,KeyValuePair<,> 不使用 readonly 实例字段,它仅使用 get 实例属性(但没有通过反射找到 private 设置器)。
      【解决方案4】:

      public string Something{get; set;} 只是语法糖;编译器实际上将其扩展为方法。因此,为了它而将所有 get; set; 字段放在所有地方没有什么意义。

      【讨论】:

        【解决方案5】:

        1) 您可以添加私有访问器来获取或设置和控制对属性的访问。

        public object MyProp {get; private set;}
        

        你可以在任何地方阅读道具,但只能在类内写

        2) 您可以将一些逻辑连接到读/写属性。在现场的情况下,你不能做任何额外的事情

        3) 不能序列化字段

        【讨论】:

        • 您也可以使用常用属性来执行此操作。
        • @Aschratt 是的,但是你不能使用字段。当然,您可以使用字段指定 readonly,但这比 private 设置器要严格一些。
        • 对不起,我认为问题是关于标准属性和自动属性之间的区别...... :) 没有害处!
        猜你喜欢
        • 2012-02-05
        • 1970-01-01
        • 1970-01-01
        • 2011-06-19
        • 1970-01-01
        • 2010-11-13
        • 1970-01-01
        • 2021-01-02
        相关资源
        最近更新 更多