Why does a recursive constructor call make invalid C# code compile? -


after watching webinar jon skeet inspects resharper, i've started play little recursive constructor calls , found, following code valid c# code (by valid mean compiles).

class foo {     int = null;     int b = appdomain.currentdomain;     int c = "string int";     int d = nonexistingmethod();     int e = invalid<method>name<<indeeed();      foo()       :this(0)  { }     foo(int v)  :this()   { } } 

as know, field initialization moved constructor compiler. if have field int = 42;, have a = 42 in all constructors. if have constructor calling constructor, have initialization code in called one.

for example if have constructor parameters calling default constructor, have assignment a = 42 in default constructor.

to illustrate second case, next code:

class foo {     int = 42;      foo() :this(60)  { }     foo(int v)       { } } 

compiles into:

internal class foo {     private int a;      private foo()     {         this.ctor(60);     }      private foo(int v)     {         this.a = 42;         base.ctor();     } } 

so main issue, code, given @ start of question, compiled into:

internal class foo {     private int a;     private int b;     private int c;     private int d;     private int e;      private foo()     {         this.ctor(0);     }      private foo(int v)     {         this.ctor();     } } 

as can see, compiler can't decide put field initialization and, result, doesn't put anywhere. note, there no base constructor calls. of course, no objects can created, , end stackoverflowexception if try create instance of foo.

i have 2 questions:

why compiler allow recursive constructor calls @ all?

why observe such behavior of compiler fields, initialized within such class?


some notes: resharper warns possible cyclic constructor calls. moreover, in java such constructor calls won't event compile, java compiler more restrictive in scenario (jon mentioned information @ webinar).

this makes these questions more interesting, because respect java community, c# compiler at least more modern.

this compiled using c# 4.0 , c# 5.0 compilers , decompiled using dotpeek.

interesting find.

it appears there 2 kinds of instance constructors:

  1. an instance constructor chains instance constructor of same type, : this( ...) syntax.
  2. an instance constructor chains instance constructor of base class. includes instance constructors no chainig specified, since : base() default.

(i disregarded instance constructor of system.object special case. system.object has no base class! system.object has no fields either.)

the instance field initializers might present in class, need copied beginning of body of instance constructors of type 2. above, whereas no instance constructors of type 1. need field assignment code.

so apparently there's no need c# compiler analysis of constructors of type 1. see if there cycles or not.

now example gives situation all instance constructors of type 1.. in situation field initaializer code not need put anywhere. not analyzed deeply, seems.

it turns out when instance constructors of type 1., can derive base class has no accessible constructor. base class must non-sealed, though. example if write class private instance constructors, people can still derive class if make instance constructors in derived class of type 1. above. however, new object creation expression never finish, of course. create instances of derived class, 1 have "cheat" , use stuff system.runtime.serialization.formatterservices.getuninitializedobject method.

another example: system.globalization.textinfo class has internal instance constructor. can still derive class in assembly other mscorlib.dll technique.

finally, regarding the

invalid<method>name<<indeeed() 

syntax. according c# rules, read as

(invalid < method) > (name << indeeed()) 

because left-shift operator << has higher precedence both less-than operator < , greater-than operator >. latter 2 operarors have same precedence, , therefore evaluated left-associative rule. if types were

myspecialtype invalid; int method; int name; int indeed() { ... } 

and if myspecialtype introduced (myspecialtype, int) overload of operator <, expression

invalid < method > name << indeeed() 

would legal , meaningful.


in opinion, better if compiler issued warning in scenario. example, unreachable code detected , point line , column number of field initializer never translated il.


Comments

Popular posts from this blog

.htaccess - First slash is removed after domain when entering a webpage in the browser -

Automatically create pages in phpfox -

c# - Farseer ContactListener is not working -