【问题标题】:How do I assign a readonly member variable in an object initializer?如何在对象初始化程序中分配只读成员变量?
【发布时间】:2020-05-19 12:52:53
【问题描述】:
class foo {
    public readonly int bar;
};
foo a = new foo() { bar = 123 };

error CS0191: A readonly field cannot be assigned to (except in a constructor or a variable initializer)

如何在上面的对象初始化器中分配bar

我能否在不必为每个类/结构编写自定义构造函数的情况下初始化只读成员?

【问题讨论】:

    标签: c# c#-4.0


    【解决方案1】:
    foo a = new foo() { bar = 123 };
    

    由编译器转换为

    foo temp = new foo();
    temp.bar = 123;
    foo a = temp;
    

    如您所见,bar 的赋值既不在 foo 构造函数中,也不在变量初始化器中。

    所以答案是:你不能。

    【讨论】:

    • 似乎是设计师的疏忽:'(
    • @tm1rbrt 不,没有疏忽——你应该了解正确的封装
    • @scibuff 对我来说似乎是一个安全的单一任务?
    • @scibuff 我认为这是一个疏忽和/或糟糕的设计。在这种情况下,编译器建议使用变量初始化器。但这不是编译器问题的解决方案。
    • @scibuff 就语言设计而言,我认为 C# 结构被认为仅以不可变形式 (stackoverflow.com/questions/441309/why-are-mutable-structs-evil) 是合理的设计是糟糕的设计,但语言的变量初始化程序实现却没有不能用这个。所以结构变量初始化器存在于语言中,但由于 CLI 而不是 Good Part™。
    【解决方案2】:

    总结其他答案的观点:错误消息没有帮助——对象初始化器不能与只读字段一起使用。

    但是,具有命名参数的构造函数可以,并且这样做的语法非常相似。  如此相似,您甚至可能会认为您已经看到了只读字段的 C# 对象初始化器(就像我一样) 当你实际看到的是这样的:

    class Foo {
        public Foo(int bar) {
            this.bar = bar;
        }
        public readonly int bar;
    };
    
    Foo a = new Foo(bar: 123);
    // instead of `new Foo() { bar = 123 };`
    

    【讨论】:

    • 没错!在搜索了一个小时并阅读了很多高票的答案后,终于找到了正确的答案,这甚至让我明白了为什么我不自觉地无法相信初始化列表不允许赋值为只读。我仍然想知道为什么构造函数中的命名参数同样有用。
    【解决方案3】:

    你在构造函数中传递值:

    public class foo 
    {
        public readonly int _bar;
    
        public foo(int bar) 
        {
            _bar = bar;
        }
    };
    
    
    var x = new foo(12345);
    

    编译器告诉你的是,你可以设置只读字段的唯一位置是在持有它的类的构造函数中,这意味着:

    • 如果您需要在对象的生命周期内更改它,那么 readonly 不是使用的正确选项
    • 如果类的每个实例都需要在只读成员变量中保存一个自定义值,那么您需要将其作为构造函数的一部分注入

    我建议将你的只读字段 public 设为这样不是一个好习惯,而只是将其公开为只有一个 getter 的公共属性。

    【讨论】:

      【解决方案4】:
      class Foo {
           private int bar;
      
           public Foo( int bar ){
               this.bar = bar;
           }
      
           public int Bar {
               get { return this.bar; }
           }
      }
      
      Foo foo = new Foo( 123 );
      

      【讨论】:

        【解决方案5】:

        你不能。你应该使用它的构造函数。 MSDN

        【讨论】:

          【解决方案6】:

          你不能。错误想告诉您可以使用的内容

          class foo {
              public readonly int bar = blabla;
          };
          

          您使用的对象初始值设定项语法只是用于调用构造函数和分配给成员的语法糖。而这对于只读成员是不允许的。


          你需要引入一个构造函数参数,然后在构造函数中赋值。 C# 非常缺乏不可变类型的语法糖。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2011-05-26
            • 2023-03-14
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-01-07
            相关资源
            最近更新 更多