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.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…