2011-01-23 81 views
6

nói rằng tôi có một lớp học mà có một tài sản đó là một cuốn từ điển < chuỗi, bool >, sử dụng một initializer đối tượng tôi có thể sử dụng cú pháp này (mà tôi nghĩ rằng trông khá sạch sẽ):bộ khởi tạo đối tượng biến đổi?

new MyClass() 
{ 
    Table = { {"test",true},{"test",false} } 
} 

Tuy nhiên, bên ngoài của trình khởi tạo Tôi không thể thực hiện việc này:

this.Table = { {"test",true},{"test",false} }; 

Tại sao trình khởi tạo lại là trường hợp đặc biệt? Tôi muốn nguy hiểm một đoán rằng nó có cái gì để làm với yêu cầu LINQ, hiệp phương sai hoặc whatnot nhưng nó cảm thấy một chút không phù hợp không thể sử dụng loại initializer ở khắp mọi nơi ...

+0

câu hỏi thú vị. –

+0

Tôi nghĩ rằng thực tế là lỗi trình biên dịch là "biểu hiện dự kiến" là một đầu mối lớn. Trong ví dụ thứ hai, cú pháp không biểu thị một biểu thức như bạn thường mong đợi, tức là không có toán tử 'new' nào. Tôi nghi ngờ rằng ví dụ đầu tiên hoạt động như nó là một trường hợp đặc biệt và trình biên dịch là thoải mái hơn về những gì tạo thành một biểu thức cú pháp. Lợi ích của các quy tắc thoải mái là cú pháp terser rất mong muốn đối với ngữ cảnh của cú pháp khởi tạo đối tượng, nó sẽ xem xét cách khác. –

Trả lời

0

Xem xét cú pháp của bạn ném một NullReferenceException khi chạy - bạn có chắc là bạn có thể sử dụng nó không?

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

public void TestMethod() 
{ 
    Test t = new Test { Table = { {"test", false} } }; //NullReferenceException 
} 

này biên dịch như sau (thông qua phản xạ):

Test <>g__initLocal3 = new Test(); 
<>g__initLocal3.Table.Add("test", 0.0M); 

Như bạn thấy, Table không được khởi tạo, do đó tạo ra một NullReferenceException khi chạy.

Nếu bạn tạo từ điển trong ctor của Test, trình khởi tạo lớp tạo ra một chuỗi các câu lệnh Add, là cú pháp trong bộ khởi tạo (cho IEnumerable s).

Điều này có thể không được giới thiệu cho mã bình thường do các tác dụng phụ không xác định mà chúng tôi không thể thấy hoặc tưởng tượng. Eric Lippert có thể giúp đỡ vì anh ta có lẽ có cái nhìn sâu sắc hơn về vấn đề này.

+2

vâng tôi biết, nhưng không phải chính xác cú pháp tương tự – Homde

+3

nhưng không phải là anh ta hỏi lý do tại sao bạn phải cung cấp 'mới Dictionary ' trước nó. –

+1

Nếu bạn tạo từ điển trong hàm dựng Kiểm tra hoặc ở nơi khác, nó sẽ không ném ngoại lệ. –

2

Giới hạn này lớn hơn LINQ. Ngay cả khi trở lại C, bạn có thể viết

int numbers[5] = {1, 2, 3, 4, 5}; 

nhưng bạn không thể sử dụng cú pháp này để gán giá trị cho mảng.

Tôi đoán về lý do đằng sau điều này trong C# là thông thường bạn không nên sử dụng cùng một tham chiếu cho hai đối tượng khác nhau. Nếu bạn cần gán bộ sưu tập mới cho tham chiếu hiện tại, có thể bạn không thiết kế mã của mình rất tốt và bạn có thể khởi tạo bộ sưu tập theo định nghĩa hoặc sử dụng hai tham chiếu riêng thay vì một.

+0

Điều này không liên quan gì đến Linq như tôi thấy. Và làm thế nào bạn có thể sử dụng cùng một tham chiếu cho hai đối tượng khác nhau? –

+0

@chibacity: Đây là những gì tôi đã nói. mko cho rằng điều này có liên quan đến LINQ, và tôi tin là không. Và bạn có thể sử dụng cùng một tham chiếu cho hai đối tượng nếu bạn chỉ định một bộ sưu tập cho nó và sau đó gán một bộ sưu tập khác thay thế, như sau: 'col = new Dictionary (...)'. Tôi nghĩ điều này làm cho mã trông tồi tệ hơn và thay vào đó bạn nên sử dụng tham chiếu mới tốt hơn. –

+0

@Tôi thấy rồi. Nó chỉ là khó hiểu đưa góc C trong C# cũng có khởi tạo mảng, nhưng ở trên không phải là một ví dụ về một initializer mảng, đó là một bộ khởi tạo bộ sưu tập. Khá khác nhau. –

11

Câu hỏi có phần khó hiểu, vì câu hỏi không liên quan gì đến LINQ, không có gì liên quan đến phương sai chung và có bộ khởi tạo bộ sưu tập cũng như bộ khởi tạo đối tượng. Câu hỏi thực sự là, theo như tôi có thể nói "tại sao việc sử dụng bộ khởi tạo bộ sưu tập ngoài biểu thức tạo đối tượng không hợp pháp?"

Nguyên tắc thiết kế có liên quan ở đây là nói chung, chúng tôi muốn hoạt động tạo và khởi tạo các đối tượng để có từ "mới" trong chúng ở đâu đó như một tín hiệu cho người đọc rằng có một sự sáng tạo đối tượng đang diễn ra ở đây. (Có, có một vài ngoại lệ đối với quy tắc này trong C#. Như một bài tập cho người đọc, hãy xem bạn có thể đặt tên cho tất cả họ không.)

Làm mọi thứ theo cách của bạn gây khó khăn hơn cho mã. Nhanh, cái này làm gì?

d = new List<int>() { 10, 20, 30 }; 
d = { 40, 50, 60 }; 

Liệu dòng thứ hai thêm 40, 50, 60 vào danh sách hiện hành?Hay nó thay thế danh sách cũ bằng một danh sách mới? Không có "mới" trong đó, do đó, người đọc có một kỳ vọng rằng một đối tượng mới đã được tạo ra?

Khi bạn nói

q = new Whatever() { MyList = { 40, 50, 60 } }; 

mà không tạo ra một danh sách mới; nó gắn thêm 40, 50, 60 vào một danh sách hiện có được chỉ định bởi hàm tạo. Cú pháp được đề xuất của bạn do đó không rõ ràng và khó hiểu về việc liệu danh sách mới có được tạo hay không.

Tính năng được đề xuất vừa khó hiểu vừa không cần thiết, do đó không thể triển khai tính năng này sớm.

+0

Bạn nói đúng, ban đầu tôi nghĩ rằng nó thực sự tạo ra một bộ sưu tập mới, không chỉ đặt giá trị của nó. Vì vậy, nó chắc chắn khó hiểu. Chỉ là một chút tò mò về hành vi khác nhau, cảm ơn cho thanh toán bù trừ nó lên – Homde

+0

-1 Tại sao chúng ta có thể khởi tạo mảng như vậy: int [] array = {1, 2, 4}; Tôi nghĩ C# của nhà phát triển đã không suy nghĩ về 'mới' từ khóa gửi tín hiệu cho người đọc. Vì vậy, bạn không thể nói TẠI SAO họ * thực sự * đã làm điều đó. –

+6

@lazyberezovsky: Đó là một trong những trường hợp đặc biệt mà tôi đã đề cập. Lưu ý rằng nó * chỉ * hoạt động trong bộ khởi tạo của một khai báo. Đối với câu hỏi lý do tại sao ủy ban thiết kế C# * thực sự * đã làm hoặc không làm điều gì đó, tôi nghi ngờ rằng tôi có * phần nào * hiểu rõ hơn về vấn đề này hơn bạn, vì tôi có ghi chú thiết kế và tôi đã thảo luận về thiết kế ngôn ngữ ít nhất hai trong số các nhà thiết kế ban đầu cho sáu đến tám giờ một tuần trong năm năm qua. –

Các vấn đề liên quan