웨비나 Jon Skeet Inspects ReSharper를 시청 한 후 , 재귀 생성자 호출을 조금 사용하기 시작했고 다음 코드가 유효한 C # 코드라는 것을 발견했습니다 (유효하게 컴파일된다는 의미입니다).
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() { }
}
우리 모두가 알고 있듯이 필드 초기화는 컴파일러에 의해 생성자로 이동됩니다. 이 같은 필드가 있다면 그래서 int a = 42;, 당신은해야합니다 a = 42에 모든 생성자. 그러나 다른 생성자를 호출하는 생성자가있는 경우 호출 된 생성자에만 초기화 코드가 있습니다.
예를 들어, 기본 생성자를 호출하는 매개 변수가있는 생성자가 a = 42있는 경우 기본 생성자에만 할당 됩니다.
두 번째 경우를 설명하기 위해 다음 코드 :
class Foo
{
int a = 42;
Foo() :this(60) { }
Foo(int v) { }
}
다음으로 컴파일됩니다.
internal class Foo
{
private int a;
private Foo()
{
this.ctor(60);
}
private Foo(int v)
{
this.a = 42;
base.ctor();
}
}
따라서 주요 문제는이 질문의 시작 부분에 제공된 내 코드가 다음과 같이 컴파일된다는 것입니다.
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();
}
}
보시다시피 컴파일러는 필드 초기화를 배치 할 위치를 결정할 수 없으므로 결과적으로 어디에도 배치하지 않습니다. 또한 base생성자 호출 이 없습니다 . 물론 개체를 만들 수 없으며 StackOverflowException의 인스턴스를 만들려고하면 항상로 끝납니다 Foo.
두 가지 질문이 있습니다.
컴파일러가 재귀 생성자 호출을 허용하는 이유는 무엇입니까?
이러한 클래스 내에서 초기화 된 필드에 대한 컴파일러의 이러한 동작을 관찰하는 이유는 무엇입니까?
참고 사항 : ReSharper 는 Possible cyclic constructor calls. 또한 Java에서 이러한 생성자 호출은 이벤트 컴파일되지 않으므로 Java 컴파일러는이 시나리오에서 더 제한적입니다 (Jon은 웨비나에서이 정보를 언급했습니다).
이것은 Java 커뮤니티와 관련하여 C # 컴파일러가 적어도 현대적 이기 때문에 이러한 질문을 더 흥미롭게 만듭니다 .
이것은 C # 4.0 및 C # 5.0 컴파일러를 사용하여 컴파일 되었으며 dotPeek를 사용하여 디 컴파일 되었습니다 .