为什么我不能初始化初始化程序中的只读变量?

cod*_*nix 17 .net c# initialization readonly c#-3.0

为什么我不能初始化初始化程序中的只读变量?以下内容不起作用:

class Foo
{
    public readonly int bar;
}

new Foo { bar=0; }; // does not work
Run Code Online (Sandbox Code Playgroud)

这是由于CLR的某些技术限制吗?

编辑

我知道它new Foo { bar=0; }是相同的new Foo().bar=0;,但是CLR强制执行"readonly",还是仅仅是编译器限制?

Dav*_*vid 17

初始化程序只是语法糖.当你写:

new Foo { bar=0; };
Run Code Online (Sandbox Code Playgroud)

(顺便说一句,这是一个语法错误,应该是这个...)

new Foo { bar=0 }
Run Code Online (Sandbox Code Playgroud)

实际发生的是:

var x = new Foo();
x.bar = 0;
Run Code Online (Sandbox Code Playgroud)

由于该属性是只读的,因此该第二个语句无效.

编辑:根据您的编辑,问题有点不清楚.根据readonly设计,财产不可设置.它建立在对象构造上.这由编译器和运行时强制执行.(不可否认,我没有对后者进行过测试,因为绕过前者需要一些技巧.)

请记住,有两个阶段的"编译".在将C#代码编译为IL代码时强制执行,并在将IL代码编译为机器代码时强制执行.

这不是CLR的技术限制,它的工作正是因为它应该给出明确的readonly声明.构造对象后,您无法设置readonly属性.


小智 14

允许readonly在初始化程序中设置a 会引入在编译时无法实施的矛盾和复杂性.我想这个限制是为了避免含糊不清.最关键的是编译时验证.

想象一下:

class Foo
{
    public readonly int bar;
    Foo () {
      // compiler can ensure that bar is set in an invoked ctor
      bar = 0;
    }
}

// compiler COULD know that `bar` was set in ctor
// and therefore this is invalid
new Foo { bar = 0; }
Run Code Online (Sandbox Code Playgroud)

现在,考虑一下:

class Foo
{
    public readonly int bar;
    Foo () {
      // imagine case where bar not set in ctor
    }
}

// compiler COULD know that `bar` is not bound yet
// therefore, this COULD be valid
new Foo { bar = 0; }

// but this COULD be proved to never be valid
new Foo();
Run Code Online (Sandbox Code Playgroud)

想象一下,上述两种情况都是统一的(例如,"通过编译器魔术"),但是,请输入泛型:

T G<T> () where T : new
{
  // What in heck should happen *at compile time*?
  // (Consider both cases above.)
  // What happens if T (Foo) changes to include/not-include setting the
  // readonly variable in the ctor?
  // Consider intermediate code that invokes G<Foo>() and this other
  // code is NOT recompiled even though Foo is--
  //   Yet a binary incompatibility has been added!
  //   No thanks!
  return new T();
}
G<Foo>();
Run Code Online (Sandbox Code Playgroud)

我相信我概述的案例显示了使用"动态" readonly方法的一些复杂性,并且在一天结束时,我认为它仅仅是一种选择的语言限制(编译器实现语言)来强制/允许编译时验证.


cod*_*nix 8

C# 9.0 最终为我们带来了仅限 init 的属性设置器:

https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-9.0/init

struct Point
{
    public int X { get; init; }
    public int Y { get; init; }
}

var p = new Point() { X = 42, Y = 13 };
Run Code Online (Sandbox Code Playgroud)


dec*_*one 5

由于readonly变量必须在构造函数中初始化,并且属性初始化程序在构造对象后执行,这是无效的.