Làm thế nào là khởi tạo từ điển C # này đúng?


64

Tôi đã vấp phải những điều sau đây và tôi tự hỏi tại sao nó không gây ra lỗi cú pháp.

var dict = new Dictionary<string, object>
{
    ["Id"] = Guid.NewGuid(),
    ["Tribes"] = new List<int> { 4, 5 },
    ["MyA"] = new Dictionary<string, object>
    {
        ["Name"] = "Solo",
        ["Points"] = 88
    }
    ["OtherAs"] = new List<Dictionary<string, object>>
    {
        new Dictionary<string, object>
        {
            ["Points"] = 1999
        }
    }
};

Lưu ý rằng "," bị thiếu giữa "MyA" và "OtherAs".

Đây là nơi xảy ra sự nhầm lẫn:

  1. Mã biên dịch.
  2. Từ điển cuối cùng "dict" chỉ chứa ba yếu tố: "Id", "Tribes" và "MyA".
  3. Giá trị cho tất cả ngoại trừ "MyA" là chính xác,
  4. "MyA" lấy giá trị khai báo cho "OtherAs", trong khi giá trị ban đầu của nó bị bỏ qua.

Tại sao điều này không bất hợp pháp? Đây có phải là do thiết kế?


1
@Steve đó là những gì anh ấy hỏi về. Tôi dán này vào sharplab và có vẻ như ban đầu OtherAsđược thêm vào như là một chìa khóa vào những gì sẽ là các MyAtừ điển. (Tên = Solo, Điểm = 88 cộng với OtherAs = Danh sách <Từ điển <chuỗi, đối tượng >>) ngoại trừ sau đó không bao giờ gán nó . Thay vào đó, nó đặt danh sách các ký tự, bây giờ chỉ chứa mục Điểm duy nhất = 1999 vào MyAvị trí ghi đè lên những gì người ta nghĩ sẽ thuộc về nó.
Pinkfloydx33

1
Liên kết quá dài để dán trong bình luận đầu tiên. Điều này thực sự kỳ lạ. sharplab.io/...
pinkfloydx33

1
Có, tôi đã thử nghiệm nó với LinqPad và nhận được kết quả tương tự. Không chắc chắn những gì đang xảy ra ở đây. Hãy xem liệu một số guru C # có thể làm sáng tỏ ở đây.
Steve

1
Nếu bạn thay đổi từ điển đầu tiên thành <string, string> and modify Points to "88" `thì bạn sẽ gặp lỗi trình biên dịch" Không thể chuyển đổi hoàn toàn loại 'System.Collections.Generic.List <System.Collections.Generic.Dixi <chuỗi, object >>' thành 'chuỗi' " mà thực sự đã giúp tôi tìm ra câu trả lời!
Pinkfloydx33

2
@OlegI Tôi không nghĩ đó là lỗi trình biên dịch. Nhiều lời giải thích tốt đã được cung cấp trong câu trả lời. Nhưng nếu bạn cố gắng var test = new Dictionary<string, object> { ["Name"] = "Solo", ["Points"] = 88 }["OtherAs"] = new List<Dictionary<string, object>> { new Dictionary<string, object> { ["Points"] = 1999 } };sẽ giải thích thêm.
MKR

Câu trả lời:


54

Dấu phẩy bị thiếu làm cho tất cả sự khác biệt. Nó làm cho bộ chỉ mục ["OtherAs"]được áp dụng trên từ điển này:

new Dictionary<string, object>
{
    ["Name"] = "Solo",
    ["Points"] = 88
}

Vì vậy, về cơ bản bạn đang nói:

new Dictionary<string, object>
{
    ["Name"] = "Solo",
    ["Points"] = 88
}["OtherAs"] = new List<Dictionary<string, object>>
{
    new Dictionary<string, object>
    {
        ["Points"] = 1999
    }
};

Lưu ý rằng đây là biểu thức gán ( x = y). Đây xlà từ điển với "Tên" và "Điểm", được lập chỉ mục với "OtherAs"yList<Dictionary<string, object>>. Một biểu thức gán ước tính giá trị được gán ( y), đó là danh sách từ điển.

Kết quả của toàn bộ biểu thức này sau đó được gán cho khóa "MyA", đó là lý do tại sao "MyA" có danh sách từ điển.

Bạn có thể xác nhận rằng đây là những gì đang xảy ra bằng cách thay đổi loại từ điển x:

new Dictionary<int, object>
{
    [1] = "Solo",
    [2] = 88
}
// compiler error saying "can't convert string to int"
// so indeed this indexer is applied to the previous dictionary
["OtherAs"] = new List<Dictionary<string, object>>
{
    new Dictionary<string, object>
    {
        ["Points"] = 1999
    }
}

Đây là mã của bạn, nhưng được định dạng lại và một số dấu ngoặc đơn được thêm vào để minh họa cách trình biên dịch đã phân tích cú pháp:

["MyA"] 
= 
(
    (
        new Dictionary<string, object>
        {
            ["Name"] = "Solo",
            ["Points"] = 88
        }["OtherAs"] 
    )
    = 
    (
        new List<Dictionary<string, object>>
        {
            new Dictionary<string, object>
            {
                ["Points"] = 1999
            }
        }
    )
)

1
Nó đã thay đổi loại giá trị của từ điển từ đó objectsang stringcho tôi một thông báo lỗi tương tự và khoảnh khắc aha đã tạo ra câu trả lời. Có vẻ như bạn đã đánh bại tôi - Tôi đổ lỗi khi gõ câu trả lời trên điện thoại của tôi :-p
Pinkfloydx33

19

Điều đang xảy ra ở đây là bạn đang tạo một từ điển và sau đó lập chỉ mục vào đó. Kết quả của biểu thức chỉ mục / gán sau đó được trả về và đó là những gì được gán vào MyAvị trí từ điển.

Điều này:

["MyA"] = new Dictionary<string, string> 
{
   ["Name"] = "Solo",
   ["Points"] = "88" 
}
["OtherAs"] = new List<Dictionary<string, object>>
{
   new Dictionary<string, object>
   {
       ["Points"] = 1999
   }
}

Có thể được chia thành mã psuedo sau:

var temp = new Dictionary<string, object>
{ 
   ["Name"] = "Solo", 
   ["Points"] = 88 
};
// indexed contains result of assignment
var indexed = temp["OtherAs"] = new List<Dictionary<string, object>>
{
   new Dictionary<string, object>
   {
      ["Points"] = 1999
   }
};
// value is set to result of assignment from previous step
["MyA"] = indexed;
// temp is discarded

Kết quả của việc gán cho bộ chỉ mục của từ điển thứ hai được trả về (phép gán trả về giá trị được gán / bên tay phải) Từ điển đó là một cục bộ tạm thời chỉ "biến mất trong ether". Kết quả của bộ chỉ mục (danh sách từ điển) là những gì được đặt vào từ điển chính cuối cùng.

Đây là một trường hợp kỳ lạ, được làm cho dễ rơi vào hơn do sử dụng objectnhư là loại giá trị từ điển.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.