2009-09-23 7 views
10

Các mã sau biên dịch, nhưng không thành công với một NullReferenceException:C# từ điển initializer biên soạn mâu thuẫn

class Test 
{ 
    public Dictionary<string, string> Dictionary { get; set; } 
} 

static void Main(string[] args) 
{ 
    var x = new Test 
    { 
     Dictionary = // fails 
     { 
      { "key", "value" }, { "key2", "value2" } 
     } 
    }; 
} 

Nếu bạn thay thế dòng được đánh dấu 'không' với những điều sau đây, nó hoạt động (như dự kiến):

Dictionary = new Dictionary<string, string> 

Có bất kỳ mục đích nào với cú pháp không thành công - nó có thể được sử dụng thành công trong một số trường hợp khác không? Hay đây là một sự giám sát trong trình biên dịch?

Trả lời

32

Không, nó không phải là một sai lầm ... đó là một lỗ hổng trong hiểu biết của bạn cú pháp khởi :)

Ý tưởng của

Dictionary = { ... } 

là đối với trường hợp người gọi có đọc truy cập đối với thuộc tính bộ sưu tập, nhưng không phải ghi quyền truy cập. Nói cách khác, các tình huống như sau:

class Test 
{ 
    private readonly Dictionary<string, string> dictionary 
     = new Dictionary<string, string>(); 
    public Dictionary<string, string> Dictionary { get { return dictionary; } } 
} 

Về cơ bản, nó kết thúc bằng lời gọi đến Thêm, nhưng không tạo bộ sưu tập mới trước. Vì vậy, mã này:

Test test = new Test { Dictionary = { { "a", "b"}, {"c", "d" } }; 

tương đương với:

Test tmp = new Test(); 
Dictionary<string, string> tmpDictionary = tmp.Dictionary; 
tmpDictionary.Add("a", "b"); 
tmpDictionary.Add("c", "d"); 
Test test = tmp; 

Một ví dụ tốt về nơi này rất hữu ích là với Controls bộ sưu tập cho một giao diện người dùng. Bạn có thể làm điều này:

Form form = new Form 
{ 
    Controls = 
    { 
     new Button { Text = "Hi" }, 
     new TextBox { Text = "There" } 
    } 
}; 

nhưng bạn có thể không thực sự thiết các Controls bất động sản, bởi vì nó chỉ đọc.

+0

Vì vậy, nó được sử dụng để thêm các mục vào một từ điển được tạo bởi hàm tạo - tôi đã nhận ra điều đó. Nhưng đó là một sử dụng kỳ lạ của toán tử equals, vì hiệu ứng là để thêm vào bất cứ điều gì đã có trong từ điển (constructor có thể đã thêm các mục đầu tiên). –

+0

Sắp xếp, có ... nhưng đồng thời nó được sử dụng để thiết lập các giá trị ban đầu trong bộ sưu tập, do đó, nó phù hợp theo cách đó. –

+0

Phải. Thiếu 'new' phải là cờ đỏ .. nhưng chưa bao giờ sử dụng cú pháp này, tôi lấy toán tử equals theo nghĩa đen. –

0

Không thành công với ngoại lệ tham chiếu null vì bạn đã khai báo biến (Từ điển) không được định nghĩa, do đó nó không có giá trị.

Khi bạn cố gắng thêm các mục nhập vào nó bằng cú pháp khởi tạo, bạn đang cố ghi dữ liệu vào đối tượng rỗng.

Khi bạn thay thế dòng bằng "= Từ điển mới ...", bạn đang tạo đối tượng mới cho Từ điển để tham chiếu và do đó bạn có thể thêm mục nhập vào thành công.

(Trong ví dụ của Jon Skeet, bộ sưu tập Controls phải đã được tạo ra bởi các Form, vì vậy nó hoạt động ok)

+0

Vâng, tất nhiên rồi. Câu hỏi của tôi là: tại sao lại cho phép cú pháp này? –

+0

Đủ công bằng.Jon trả lời câu hỏi của bạn vì vậy tôi nghĩ tôi sẽ điền vào lý do trong trường hợp bạn không hiểu thất bại. –

4

Bạn vẫn có thể sử dụng cú pháp mà bạn muốn trong một constructor:

Dictionary<string, string> dictionary = new Dictionary<string, string> 
      { 
       {"a", "b"}, 
       {"c", "d"} 
      };