2010-10-01 17 views
16

Mã này biên dịch thành công, nhưng tôi nghĩ rằng nó sẽ không biên dịch được. Ngoài ra, khi bạn chạy nó, bạn sẽ có được một NullReferenceException. Mã bị thiếu là "thanh mới" trong quá trình khởi tạo thuộc tính Bar.Đây có phải là lỗi trong trình biên dịch C# 4.0 không?

class Bar 
{ 
    public string Name { get; set; } 
} 

class Foo 
{ 
    public Bar Bar { get; set; } 
} 


class Program 
{ 
    static void Main(string[] args) 
    { 
     var foo = new Foo 
         { 
          Bar = { Name = "Hello" } 
         }; 
    } 
} 

Đây có phải là lỗi đã biết không?

+3

Tại sao bạn nghĩ nó nên thất bại trong việc biên dịch? Tôi sẽ không cho rằng đó là lỗi trình biên dịch. –

+0

Vâng, đó là một tính năng đã biết. – leppie

+0

Bởi vì không có cách nào có thể làm việc này – Maxm007

Trả lời

41

Tại sao bạn cho rằng không thể biên dịch? Nó là cú pháp khởi tạo đối tượng lồng nhau, và đó là trách nhiệm của mã máy khách để cung cấp một giá trị hợp lệ để khởi tạo.

Từ các tài liệu:

C# đặc tả 7.5.10.2 "Object initializers"

Một initializer thành viên đó xác định một đối tượng khởi tạo sau dấu bằng là một đối tượng khởi tạo lồng nhau, tức là một khởi của một đối tượng nhúng. Thay vì chỉ định một giá trị mới cho lĩnh vực hoặc tài sản, các bài tập trong initializer đối tượng lồng nhau được coi là nhiệm vụ cho các thành viên của trường hoặc tài sản

+1

Chà, tôi không biết! Cảm ơn rất nhiều. –

+0

Mô tả tuyệt vời về vấn đề này. – NotMe

+0

Cảm ơn bạn. Câu trả lời tốt! –

3

Các new là hưởng ứng nhiệt liệt trong một đối tượng initializer:

object-creation-expression: 
    new type ( argument-list(opt) ) object-or-collection-initializer(opt) 
    new type object-or-collection-initializer 

object-or-collection-initializer: 
    object-initializer 
    collection-initializer 

object-initializer: 
    { member-initializer-list(opt) } 
    { member-initializer-list , } 

initializer-value: 
    expression 
    object-or-collection-initializer 

Đó là điều cuối cùng quan trọng nhất. Nó đại diện cho phía bên tay phải của cú pháp property = value của bạn. Điều này có nghĩa là phía bên phải có thể là biểu thức C# bình thường (với toán tử new) hoặc một bộ phận kích thích khác. Trong trường hợp đó, tất cả những gì bạn cần là niềng răng mở và đóng.

+0

Vâng, hiểu về cái mới không cần thiết nhưng đâu là loại cho thanh? – Maxm007

+0

Nó được phỏng đoán vì loại được biết dựa trên thuộc tính đang được khởi tạo. –

+0

vì vậy nếu nó suy ra nó một thanh của nó, và sau đó giả định New Bar của nó, tại sao nó ném nullrefexception. – Maxm007

1

Bar là một tài sản của Foo, vì vậy nó được cho phép bạn truy cập vào nó và gán thuộc tính name tại thời gian biên dịch, nhưng tại thời điểm chạy nó kiểm tra các trường hợp hợp lệ Bar mà không có mặt để ném ngoại lệ tham chiếu null, nó sẽ là trường hợp với bất kỳ phiên bản C# nào.

16

Không có lỗi này.

Nếu bạn muốn nó chạy bạn hãy đặt new trước Bar (giống như bạn đã làm cho Foo trước bộ khởi tạo) hoặc bạn tạo đối tượng Bar trong hàm tạo của Foo.

Trình khởi tạo đối tượng về cơ bản chỉ là đường cú pháp.

này:

var foo = new Foo 
      { 
       Bar = { Name = "Hello" } 
      }; 

là giống hệt nhau như thế này:

var foo = new Foo(); 
foo.Bar.Name = "Hello"; 
2

Nếu bạn thay đổi mã của bạn để tương đương sau đây, bạn cũng sẽ nhận được một lỗi thời gian chạy của một NullReferenceException thay vì một biên dịch lỗi/cảnh báo thời gian.

static void Main(string[] args) { 
    Foo foo2 = new Foo(); 
    foo2.Bar.Name = "test"; 
} 

Hiệu ứng giống nhau, Bar không bao giờ được khởi tạo đúng cách. Bây giờ, từ góc độ của một nhà biên dịch biên dịch, việc xác định xem Bar có được khởi tạo đúng cách trước khi sử dụng hay không là vô cùng khó khăn.

2
... 
Bar = { Name = "Hello"} 
... 

có nghĩa là: Foo.Bar.Name="Hello" không: {Foo.Bar=new Bar(); Foo.Bar.Name="Hello";}

này sẽ biên dịch và sẽ không ném bất kỳ ngoại lệ, vì vậy nó không phải là một lỗi, bạn chỉ cần khởi tạo một đối tượng unexisting:

class Bar 
{ 
    public string Name; 
} 
class Foo 
{ 
private Bar _bar = new Bar(); 
public Bar Bar 
{ 
    get { return _bar; } 
    set { _bar = value; } 
} 
} 
class Program 
{ 
static void Main(string[] args) 
{ 
    Foo foo = new Foo 
    { 
    Bar = { Name = "Hello"} 
    }; 
} 
} 
0

Tôi tạo một mẫu làm việc .

dễ dàng, chỉ có thêm một "Bar mới()" của nó một nó làm việc tốt


class Bar 
{ 
    public string Name { get; set; } 
} 

class Foo 
{ 
    public Bar Bar { get; set; } 
} 


class Program 
{ 
    static void Main(string[] args) 
    { 
     var foo = new Foo 
         { 
          Bar = new Bar() { Name = "Hello" } 
         }; 

     Console.WriteLine(foo.Bar.Name); 
     Console.ReadLine(); 
    } 
}