2013-06-26 40 views
9

Tôi vừa tìm thấy mã lạ trong mã Jeffrey Richter (CLR qua C# 4.0, trang 257) và có hiểu lầm tại sao nó hoạt động như vậy.nhận và thiết lập sự hiểu lầm trong khởi tạo: Jeffrey Richter, CLR qua C#

public sealed class Classroom 
    { 
     private List<String> m_students = new List<String>(); 
     public List<String> Students { get { return m_students; } } 

     public Classroom() { } 
    } 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      Classroom classroom = new Classroom { 
       Students = { "Jeff", "Kristin" } 
      }; 

      foreach (var student in classroom.Students) 
       Console.WriteLine(student); 
     } 
    } 

Kết quả:

Jeff 
Kristin 

Như bạn có thể thấy, chúng ta có một tài sản accessor có tên là 'Học sinh', mà chỉ có getter (! Không setter), nhưng trong chức năng 'Main', khi chúng tôi muốn khởi tạo biến 'lớp học', chúng tôi khởi tạo trường 'Học sinh' của loại 'Lớp học':

Classroom classroom = new Classroom { 
    Students = { "Jeff", "Kristin" } 
}; 

Tôi luôn nghĩ rằng khi một biến trong 'bên trái' của biểu thức (int i = 1), sau đó trình biên dịch nên truy cập vào hàm setter, và khi trong 'right-side' (int x = i + 2) để hàm getter.

Tại sao mã của Jeffrey lại có hành vi thú vị như vậy (có thể nó chỉ dành cho tôi? Xin lỗi nếu có).

Trả lời

22

Từ phần 7.6.10.2 của C# 5 spec:

Một initializer thành viên đó quy định cụ thể một initializer bộ sưu tập sau dấu bằng là một khởi của một bộ sưu tập nhúng. Thay vì gán một bộ sưu tập mới cho trường hoặc thuộc tính, các phần tử được đưa ra trong bộ khởi tạo được thêm vào bộ sưu tập được tham chiếu bởi trường hoặc thuộc tính. Trường hoặc thuộc tính phải thuộc loại bộ sưu tập đáp ứng các yêu cầu được quy định trong §7.6.10.3.

Vì vậy, mã này:

Classroom classroom = new Classroom { 
    Students = { "Jeff", "Kristin" } 
}; 

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

Classroom tmp = new Classroom(); 
tmp.Students.Add("Jeff"); 
tmp.Students.Add("Kristin"); 
Classroom classroom = tmp; 

Về cơ bản, = trong một initializer đối tượng không phải là chính xác giống như một câu lệnh gán độc lập.

EDIT: Mã này

Classroom classroom = new Classroom { 
    Students = new List<string> { "Jeff", "Kristin" } 
}; 

sẽ thất bại trong việc biên dịch, vì điều đó sẽ cố gắng gọi một setter cho Student.

+1

Huy hiệu cho câu trả lời nhanh chóng trong việc cải thiện chỉnh sửa ở đâu? – Michael

+0

Đáng chú ý rằng 'Học sinh = danh sách mới ()' sẽ đưa ra một lỗi biên dịch thời gian là một, trên khuôn mặt của nó, ban đầu có thể mong đợi trong trường hợp khác này? –

+1

Kiến thức này đã đáp ứng hạn ngạch "Chỉnh sửa C# thực tế trong ngày" của tôi. – Chris