2016-08-23 16 views
5

MSDN khẳng định rằng:Sự khác biệt giữa Collection Initializer Câu lệnh

Bằng cách sử dụng một initializer bộ sưu tập bạn không cần phải xác định nhiều cuộc gọi đến các phương thức Add của lớp trong mã nguồn của bạn; trình biên dịch thêm các cuộc gọi.

Họ cũng đưa ra ví dụ này, bằng cách sử dụng cú pháp khởi tạo bộ sưu tập mới với dấu ngoặc:

var numbers = new Dictionary<int, string> { 
    [7] = "seven", 
    [9] = "nine", 
    [13] = "thirteen" 
}; 

Tuy nhiên, khi kiểm tra mã IL được tạo ra, có vẻ như rằng mã này không ở tất cả các kết quả trong bất kỳ cuộc gọi với phương pháp Add, nhưng để thay cho một set_item, như vậy:

IL_0007: ldstr  "seven" 
IL_000c: callvirt  instance void class [mscorlib]System.Collections.Generic.Dictionary`2<int32, string>::set_Item(!0/*int32*/, !1/*string*/) 

các "cũ" cú pháp với dấu ngoặc nhọn trong tương phản cho những điều sau đây:

// C# code: 
var numbers2 = new Dictionary<Int32, String> 
{ 
    {7, "seven"}, 
    {9, "nine"}, 
    {13, "thirteen"} 
}; 

// IL code snippet: 
// ---------- 
// IL_0033: ldstr  "seven" 
// IL_0038: callvirt  instance void class [mscorlib]System.Collections.Generic.Dictionary`2<int32, string>::Add(!0/*int32*/, !1/*string*/) 

... Như bạn có thể thấy, gọi tới số Add là kết quả như mong đợi. (Người ta chỉ có thể giả định rằng văn bản trên MSDN được đề cập ở trên vẫn chưa được cập nhật.)

Tôi đã phát hiện ra một trường hợp sự khác biệt này thực sự quan trọng, và đó là với kỳ quặc System.Collections.Specialized.NameValueCollection. Điều này cho phép một khóa trỏ đến nhiều hơn một giá trị. Khởi tạo có thể được thực hiện trong cả hai cách:

const String key = "sameKey"; 
const String value1 = "value1"; 
const String value2 = "value2"; 

var collection1 = new NameValueCollection 
{ 
    {key, value1}, 
    {key, value2} 
}; 

var collection2 = new NameValueCollection 
{ 
    [key] = value1, 
    [key] = value2 
}; 

... Nhưng vì sự khác biệt về chỉ cách cựu thực sự gọi là NameValueCollection::Add(string, string), kết quả khác nhau khi nhìn vào nội dung của từng bộ sưu tập;

collection1 [key] = "value1, value2"

collection2 [key] = "value2"

tôi nhận ra rằng có một mối liên hệ giữa cú pháp cũ và giao diện IEnumerable, và cách trình biên dịch tìm phương thức Add bằng cách đặt tên quy ước etcetera. Tôi allso nhận ra những lợi ích của bất kỳ loại indexer đang phải chịu cú pháp mới, như đã thảo luận trong this SO answer trước đây.

Có lẽ đây là tất cả các tính năng được mong đợi, từ quan điểm của bạn, nhưng các tác động đã không xảy ra với tôi và tôi rất tò mò muốn biết thêm.

Vì vậy, tôi tự hỏi nếu có nguồn tài liệu tại MSDN hoặc ở nơi khác làm rõ sự khác biệt này trong hành vi đi kèm với lựa chọn cú pháp. Tôi cũng tự hỏi nếu bạn biết về bất kỳ ví dụ khác, nơi sự lựa chọn này có thể có tác động như khi khởi tạo một NameValueCollection.

+4

Các tài liệu bạn tham khảo để làm nói điều này trên cú pháp 'mới': * Bạn có thể chỉ định các yếu tố được lập chỉ mục nếu bộ sưu tập hỗ trợ lập chỉ mục. *. Với tôi, điều đó ngụ ý nó sẽ sử dụng bộ chỉ mục để thực hiện cài đặt. –

+0

@CharlesMager Tôi sắp sửa đăng một nội dung tương tự sau khi nhìn thấy [this] (http://stackoverflow.com/questions/28076127/c6s-new-collection-initializer-clarification) – Rawling

+0

@CharlesMager Đúng là những gì bạn nói, nhưng tôi 'd hầu như không gọi đó là một "làm sáng tỏ", có lẽ tiết kiệm cho người đã giác ngộ;) Ngoài ra, câu hỏi - theo như sự khác biệt trong hành vi đi - rõ ràng chỉ áp dụng cho các loại chịu sự "lập chỉ mục" và "thêm", cái gì đó cũng không được thảo luận trên trang đó. –

Trả lời

4

Tôi giả sử để làm rõ tối đa, bạn phải đi đến đặc điểm kỹ thuật. Thông số C# 6 không được phát hành chính thức nhưng có sẵn unofficial draft.

Điều thú vị ở đây là, mặc dù vị trí của nó trong Hướng dẫn lập trình, cú pháp chỉ mục là không trình khởi tạo bộ sưu tập, nó là bộ khởi tạo đối tượng.Từ 7.6.11.3 'Collection Initializers':

Một initializer bộ sưu tập bao gồm một chuỗi các initializers yếu tố, bao bọc bởi {và} thẻ và cách nhau bằng dấu phẩy . Mỗi bộ khởi tạo phần tử chỉ định một phần tử được thêm vào đối tượng bộ sưu tập đang được khởi tạo và bao gồm danh sách các biểu thức kèm theo {và} mã thông báo và được phân tách bằng dấu phẩy. ... Đối tượng bộ sưu tập mà bộ khởi tạo bộ sưu tập được áp dụng phải thuộc loại thực hiện System.Collections.IEnumerable hoặc một lỗi biên dịch xảy ra. Đối với mỗi yếu tố quy định theo thứ tự, các bộ sưu tập initializer gọi một phương pháp Add trên đối tượng mục tiêu với danh sách biểu hiện của initializer yếu tố dạng danh sách luận

Và từ 7.6.11.2 'Object Intializers':

Một bộ khởi tạo đối tượng bao gồm một chuỗi các trình khởi tạo thành viên, được bao quanh bởi {và} mã thông báo và được phân cách bằng dấu phẩy . Mỗi member_initializer chỉ định một mục tiêu cho việc khởi tạo. Số nhận dạng phải đặt tên trường hoặc thuộc tính có thể truy cập của đối tượng đang được khởi tạo, trong khi đối số_list được đặt trong ngoặc vuông phải chỉ định đối số cho chỉ mục có thể truy cập trên đối tượng đang được khởi tạo.

Cầm lấy cái này làm ví dụ:

public class ItemWithIndexer 
{ 
    private readonly Dictionary<string, string> _dictionary = 
     new Dictionary<string, string>(); 

    public string this[string index] 
    { 
     get { return _dictionary[index]; } 
     set { _dictionary[index] = value; } 
    } 
} 

Lưu ý rằng lớp này không đáp ứng các yêu cầu để có một khởi tạo bộ sưu tập áp dụng: nó không thực hiện IEnumerable hoặc có một phương pháp Add, vì vậy bất kỳ cố gắng khởi tạo theo cách này sẽ dẫn đến lỗi biên dịch. Đây đối tượng nhắm vào indexer initializer sẽ biên dịch và làm việc, tuy nhiên (xem this fiddle):

var item = new ItemWithIndexer 
{ 
    ["1"] = "value" 
}; 
Các vấn đề liên quan