Why can't I initialize readonly variables in a

2020-04-02 05:09发布

Why can't I initialize readonly variables in a initializer? The following doesn't work as it should:

class Foo
{
    public readonly int bar;
}

new Foo { bar=0; }; // does not work

Is this due to some technical limits of the CLR?

EDIT

I know that new Foo { bar=0; } is the same as new Foo().bar=0;, but is "readonly" enforced by the CLR, or is it just a compiler limitation?

10条回答
混吃等死
2楼-- · 2020-04-02 05:41

According to this page, the CLR default-constructs the object first before processing the initializer list, and you are therefore assigning to bar twice (once on default construction, once when the initializer is processed).

查看更多
Evening l夕情丶
3楼-- · 2020-04-02 05:45

Because an initializer is equivalent to

var foo = new Foo();
foo.bar=0;

It is a rewrite behind the scenes.

查看更多
女痞
4楼-- · 2020-04-02 05:48

I know this isn't a direct answer to the poster's question, but the newer version of C# now allows for direct initialization from the property itself as follows.

public int bar { get; set; } = 0;

Again, I'm aware this doesn't solve the readonly issue as identified (and solved) above.

查看更多
来,给爷笑一个
5楼-- · 2020-04-02 05:50

Allowing a readonly to be set in an initializer introduces contradictions and complications that can't be enforced at compile-time. I imagine the restriction is to avoid ambiguity. The big key is compile-time validation.

Imagine this:

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; }

Now, consider:

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();

Imagine that both of the above cases are unified (say, "by compiler magic"), however, enter in generics:

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>();

I believe the cases I have outlined show some complications of using a "dynamic" readonly approach and, at the end of the day, I believe it is merely a chosen language restriction (compilers implement languages) to enforce/allow compile-time validation.

查看更多
登录 后发表回答