【问题标题】:Property with getter only vs. with getter and private setter仅具有 getter 的属性与具有 getter 和私有 setter 的属性
【发布时间】:2016-01-27 11:08:31
【问题描述】:

这些是一样的吗?

public string MyProp { get; }

对比

public string MyProp { get; private set; }

我的意思是在两个版本中,属性都可以在自己的类中设置,但对其他类是只读的?

【问题讨论】:

  • 第一个在类内也是只读的。
  • 第一个会出现错误。试试看。
  • @OrelEraki 不适用于 C# 6.0。第一个是只读自动实现属性的示例。您只能设置它的初始值,不能更改它。但是,您可以在类中更改第二个
  • 对于没有 setter 的属性,您只能从构造函数中 set 值。而private setter 可以通过任何方法来改变值。带有 getter-only 的属性是一种readonly(不可变)属性,您设置一次就忘记了(因为您以后无法更改它)。
  • 这是一个有趣的问题。只读属性和具有私有设置器的属性有什么区别?第一个是只读的,第二个只能私有设置。我的意思是,这就是代码所说的以及它是什么,所以......问题到底是什么?好的,第一个是新语法。对于这种语法,这将是一个完全不同的问题。

标签: c#


【解决方案1】:

public string MyProp { get; } - 这是在 C# 6.0 中引入的。 此类属性称为只读自动属性。对此类成员的赋值只能作为声明的一部分或在同一类的构造函数中发生。您可以在that MSDN articleJon Skeet blog. 中阅读有关它的详细说明。正如该文章中所述,此类属性自动解决了四个问题:

  • 只读定义的支持字段
  • 在构造函数中初始化支持字段
  • 属性的显式实现(而不是使用自动属性)
  • 返回支持字段的显式 getter 实现

public string MyProp { get; private set; } - 这意味着该属性在在这个类之外是只读的,但是你可以在这个类里面改变它的值。 p>

顺便说一句,您可以使用 C# 6.0 中再次引入的新自动初始化语法来设置只读自动属性值:

public string MyProp { get; } = "You cannot change me";

对于以前的C#版本,相当于这段代码:

private readonly string myProp = "You cannot change me"
public string MyProp { get { return myProp ; } }

或者,在 C# 6.0 中:

public string MyProp { get; }
protected MyClass(string myProp, ...)
{
    this.MyProp = myProp;
    ...
}

在以前的版本中是这样的:

private readonly string myProp;
public string MyProp { get { return myProp; } }
protected MyClass(string myProp, ...)
{
    this.myProp = myProp;
    ...
}

【讨论】:

  • 第一个只能在C# 6的构造函数中设置初始值。
  • @ChocapicSz 在 C#6 中??不,你不对。 C sharp 6.0 将为您处理这个问题。
  • @ChocapicSz:Farhad 的样本 ctor 中的设置值。这只是另一种形式的语法。
  • @Farhad Jabiyev:嗯,我已经测试过了,除了构造函数之外,它不能从其他地方设置。
  • @ChocapicSz 表示msdn不对:msdn.microsoft.com/en-gb/magazine/dn802602.aspx
【解决方案2】:

在第一种情况下,没有人可以设置属性值,在第二种情况下,至少类本身可以更改它。话虽如此,只有第一个是真正的“只读”属性。

但是考虑将它与只读后端字段结合起来:

private readonly string field;
public string MyProp { get { return this.field; } }

现在任何更改属性本身或支持字段值的尝试都将失败。这与 C#6 中引入的语法相同,其中烘焙字段被自动添加为 reradonly:

public string MyProp { get; }

但是,正如您已经假设其他类的两个属性一样,意思是不能以任何方式修改。

【讨论】:

    【解决方案3】:

    在 C# 6.0 中:

    public class MyClass
    {
        public int MyProp1 { get; }
        public int MyProp2 { get; private set; }
    
        public MyClass()
        {
            // OK
            MyProp1 = 1;
            // OK
            MyProp2 = 2;
        }
    
        public void MyMethod()
        {
            // Error CS0200  Property or indexer 'MyClass.MyProp1' cannot be assigned to --it is read only
            MyProp1 = 1;
            // OK
            MyProp2 = 2;
        }
    }
    

    在早期版本的 C# 中,第一个属性甚至无法编译:

    错误 1 ​​'MyClass.MyProp1.get' 必须声明一个主体,因为它不是 标记为摘要或外部。自动实现的属性必须 定义 get 和 set 访问器。

    【讨论】:

    • 您没有使用C# 6.0(就像 OP 似乎那样),因此您会收到此错误。
    【解决方案4】:

    这些属性的值只能在构造函数中定义:

    // C#, all versions
    private readonly int _foo;
    public int Foo
    {
        get { return _foo; }
    }
    
    // C#, version 6+
    // actually, this is the same as above, but backing field is generated 
    // for you by compiler
    public int Foo { get; }
    

    注意,如果你知道backing field的名字,你可以通过反射改变its的值,这样会改变属性getter的结果,但是这段代码会失败,因为没有二传手:

    typeof(SomeType).GetProperty("Foo").SetValue(bar, 1)
    

    此属性的值可以在任何声明类型的方法中定义,但也可以使用反射轻松更改它,无需了解支持字段,因为有 setter:

    // this will work fine: typeof(SomeType).GetProperty("Foo").SetValue(bar, 1)
    public int Foo { get; private set; }
    

    换句话说:主要区别在于,第一个只有 get 方法,而第二个有 get 和 set 方法。

    【讨论】:

      【解决方案5】:

      案例 1:没有 setter,自动实现的属性只能在声明属性时设置,或者在构造函数内部作为支持属性创建。因此,充当只读字段。
      情况 2:没有设置器,一个不是自动实现的属性,只能在声明该属性时设置,因为没有创建支持字段。
      案例 3:使用私有 setter,可以在类中的任何位置设置属性。

      【讨论】:

        猜你喜欢
        • 2017-06-27
        • 1970-01-01
        • 2018-07-16
        • 1970-01-01
        • 2023-03-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多