Después de ver el seminario web Jon Skeet Inspects ReSharper , comencé a jugar un poco con las llamadas recursivas al constructor y descubrí que el siguiente código es un código C # válido (por válido me refiero a que se compila).
class Foo
{
int a = null;
int b = AppDomain.CurrentDomain;
int c = "string to int";
int d = NonExistingMethod();
int e = Invalid<Method>Name<<Indeeed();
Foo() :this(0) { }
Foo(int v) :this() { }
}
Como probablemente todos sabemos, el compilador mueve la inicialización del campo al constructor. Entonces, si tiene un campo como int a = 42;, lo tendrá a = 42en todos los constructores. Pero si tiene un constructor llamando a otro constructor, tendrá el código de inicialización solo en uno llamado.
Por ejemplo, si tiene un constructor con parámetros que llaman al constructor predeterminado, solo tendrá asignación a = 42en el constructor predeterminado.
Para ilustrar el segundo caso, el siguiente código:
class Foo
{
int a = 42;
Foo() :this(60) { }
Foo(int v) { }
}
Compila en:
internal class Foo
{
private int a;
private Foo()
{
this.ctor(60);
}
private Foo(int v)
{
this.a = 42;
base.ctor();
}
}
Entonces, el problema principal es que mi código, dado al comienzo de esta pregunta, está compilado en:
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();
}
}
Como puede ver, el compilador no puede decidir dónde colocar la inicialización del campo y, como resultado, no lo coloca en ninguna parte. También tenga en cuenta que no hay basellamadas al constructor. Por supuesto, no se pueden crear objetos y siempre terminará con StackOverflowExceptionsi intenta crear una instancia de Foo.
Tengo dos preguntas:
¿Por qué el compilador permite llamadas recursivas al constructor?
¿Por qué observamos tal comportamiento del compilador para campos, inicializados dentro de dicha clase?
Algunas notas: ReSharper le advierte con Possible cyclic constructor calls. Además, en Java, tales llamadas al constructor no compilan eventos, por lo que el compilador de Java es más restrictivo en este escenario (Jon mencionó esta información en el seminario web).
Esto hace que estas preguntas sean más interesantes, porque con todo respeto a la comunidad Java, el compilador de C # es al menos más moderno.
Esto fue compilado usando compiladores C # 4.0 y C # 5.0 y descompilado usando dotPeek .