2017-02-01 14 views
7

Gần đây, tôi tình cờ gặp một số mã trông như thế này:đường cú pháp để thêm các mục vào bộ sưu tập trong initialisers đối tượng

public class Test 
{ 
    public ICollection<string> Things { get; set; } 

    public Test() 
    { 
     Things = new List<string> { "First" }; 
    } 

    public static Test Factory() 
    { 
     return new Test 
     { 
      Things = { "Second" } 
     }; 
    } 
} 

Calling Test.Factory() kết quả trong một đối tượng Test với một bộ sưu tập Things chứa cả "First""Second".

Dường như dòng Things = { "Second" } gọi phương thức AddThings. Nếu số ICollection được đổi thành IEnumerable, có lỗi cú pháp nêu rõ "IEnumerable<string> does not contain a definition for 'Add'".

Cũng rõ ràng là bạn chỉ có thể sử dụng loại cú pháp này trong trình khởi tạo đối tượng. Mã như thế này không hợp lệ:

var test = new Test(); 
test.Things = { "Test" }; 

Tên của tính năng này là gì? Phiên bản C# được giới thiệu ở đâu? Tại sao nó chỉ có sẵn trong bộ khởi tạo đối tượng?

+0

Tôi có thể đặt cược nó đã được giới thiệu trong C# 6.0 nhưng tôi không thể tìm thấy bất kỳ thông tin nào về nó. – MistyK

+2

Nó được gọi là [bộ khởi tạo bộ sưu tập] (https://msdn.microsoft.com/en-us/library/bb384062.aspx) và tôi chắc chắn nó đã sớm hơn C# 6, nhưng không thể nói chính xác. –

+0

http://geekswithblogs.net/BlackRabbitCoder/archive/2015/05/08/c.net-little-wonders-indexer-initializer-syntax.aspx - đó là C# 6.0 – MistyK

Trả lời

5

Nó được gọi là collection initializer và được thêm vào trong C# 3 language specifications (phần 7.5.10.3 lúc giới thiệu, phần 7.6.10.3 trong thông số kỹ thuật hiện tại). Cụ thể, mã bạn sử dụng sử dụng bộ khởi tạo bộ sưu tập được nhúng.

Trình khởi tạo bộ sưu tập thực sự chỉ cần gọi phương thức Add, được yêu cầu theo thông số kỹ thuật.

Như Quantic nhận xét, các thông số kỹ thuật nói:

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.

Điều đó giải thích kết quả không mong muốn của bạn khá tốt.

Tại sao nó chỉ khả dụng trong bộ khởi tạo đối tượng?

Vì nó không có ý nghĩa ở nơi khác. Bạn chỉ có thể gọi phương thức Add thay vì sử dụng các công cụ khởi tạo cho một thứ khác ngoài khởi tạo.

+0

Chỉ cần cho đầy đủ, số phần của spec hiện tại (phiên bản 5.0) để xem là 7.6.10.3 –

+1

Cú pháp 'Things = {" Second "}' cụ thể hơn là "bộ khởi tạo bộ sưu tập nhúng", như đã nói ở đây spec: "Bộ khởi tạo thành viên chỉ định bộ khởi tạo bộ sưu tập sau dấu bằng là khởi tạo bộ sưu tập được nhúng. Thay vì gán 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 trình khởi tạo sẽ được thêm vào bộ sưu tập được tham chiếu bởi trường hoặc tài sản ". Ví dụ gần nhất của cú pháp này tôi đã thấy là trong cùng một phần của spec nhưng đối với một "bộ khởi tạo đối tượng lồng nhau": 'P1 = {X = 0, Y = 1}'. – Quantic

+0

Thật vậy, bắt tốt @Quantic Cập nhật! –

1

Vì Patrick đã đề cập đến bộ khởi tạo bộ sưu tập liên tục gọi Add trong danh sách.Điều này giả định tài sản của bạn đã được khởi tạo bởi một nhà xây dựng cho phù hợp:

public class MyClass 
{ 
    public List<MyType> TheList { get; private set; } 
    public MyClass() 
    { 
     this.TheList = new List<MyType>(); 
    } 
} 

Nếu không có constructor mà khởi danh sách của bạn, bạn sẽ nhận được một NullReferenceException trong tuyên bố sau:

test.Things = { "Test" }; 

Tuy nhiên đây là một cái gì đó khác với những điều sau đây:

var m = new MyClass { TheList = new List<MyType> { ... } }; 

trong trường hợp này bạn sẽ truy cập chuyên nghiệp perties setter. Không có (hoặc chỉ một số private như trong ví dụ của tôi) dẫn đến lỗi trình biên dịch.

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