Sau khi xem hội thảo trên web Jon Skeet Kiểm tra ReSharper , tôi bắt đầu chơi một chút với các lệnh gọi hàm tạo đệ quy và nhận thấy rằng đoạn mã sau là mã C # hợp lệ (hợp lệ, tôi có nghĩa là nó biên dịch).
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() { }
}
Như chúng ta có thể đã biết, khởi tạo trường được trình biên dịch chuyển vào hàm khởi tạo. Vì vậy, nếu bạn có một trường như thế int a = 42;, bạn sẽ có a = 42trong tất cả các hàm tạo. Nhưng nếu bạn có một hàm tạo gọi một hàm tạo khác, bạn sẽ có mã khởi tạo chỉ trong một hàm được gọi.
Ví dụ: nếu bạn có hàm tạo với các tham số gọi hàm tạo mặc định, bạn sẽ chỉ có quyền gán a = 42trong hàm tạo mặc định.
Để minh họa trường hợp thứ hai, mã tiếp theo:
class Foo
{
int a = 42;
Foo() :this(60) { }
Foo(int v) { }
}
Biên dịch thành:
internal class Foo
{
private int a;
private Foo()
{
this.ctor(60);
}
private Foo(int v)
{
this.a = 42;
base.ctor();
}
}
Vì vậy, vấn đề chính, là mã của tôi, được đưa ra ở đầu câu hỏi này, được biên dịch thành:
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();
}
}
Như bạn có thể thấy, trình biên dịch không thể quyết định nơi đặt khởi tạo trường và do đó, không đặt nó ở đâu. Cũng lưu ý, không có baselệnh gọi hàm tạo. Tất nhiên, không có đối tượng nào có thể được tạo, và bạn sẽ luôn kết thúc StackOverflowExceptionnếu bạn cố gắng tạo một phiên bản của Foo.
Tôi có hai câu hỏi:
Tại sao trình biên dịch lại cho phép gọi hàm tạo đệ quy?
Tại sao chúng ta quan sát hành vi như vậy của trình biên dịch cho các trường, được khởi tạo trong lớp như vậy?
Một số lưu ý: ReSharper cảnh báo bạn với Possible cyclic constructor calls. Hơn nữa, trong Java các lệnh gọi hàm tạo như vậy sẽ không biên dịch sự kiện, vì vậy trình biên dịch Java bị hạn chế hơn trong trường hợp này (Jon đã đề cập thông tin này tại hội thảo trên web).
Điều này làm cho những câu hỏi này trở nên thú vị hơn, bởi vì đối với cộng đồng Java, trình biên dịch C # ít nhất là hiện đại hơn.
Điều này được biên dịch bằng cách sử dụng trình biên dịch C # 4.0 và C # 5.0 và được dịch ngược bằng dotPeek .