Bagaimana inisialisasi kamus C # ini benar?

64

Saya menemukan berikut ini dan saya bertanya-tanya mengapa itu tidak menimbulkan kesalahan sintaksis.

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
        }
    }
};

Perhatikan bahwa "," tidak ada di antara "MyA", dan "OtherAs".

Di sinilah kebingungan terjadi:

  1. Kode mengkompilasi.
  2. Kamus terakhir "dict" hanya berisi tiga elemen: "Id", "Tribes", dan "MyA".
  3. Nilai untuk semua kecuali "MyA" benar,
  4. "MyA" mengambil nilai yang dinyatakan untuk "OtherAs", sementara nilai aslinya diabaikan.

Mengapa ini tidak ilegal? Apakah ini berdasarkan desain?

Dantte
sumber
1
@ Sveve itu yang dia tanyakan. Saya disisipkan ini ke sharplab dan sepertinya awalnya OtherAsakan ditambahkan sebagai kunci ke dalam apa yang akan menjadi yang MyAkamus. (Nama = Solo, Poin = 88 plus OtherAs = Daftar <Kamus <string, objek >>) kecuali kemudian tidak pernah menetapkannya . Alih-alih itu menempatkan daftar dicts, sekarang hanya berisi entri Points = 1999 tunggal ke dalam MyAslot yang menimpa apa yang dipikirkan orang di sana.
pinkfloydx33
1
Tautan terlalu panjang untuk disisipkan dalam komentar pertama. Ini memang aneh. sharplab.io/…
pinkfloydx33
1
Ya, saya telah mengujinya dengan LinqPad dan mendapatkan hasil yang sama. Tidak yakin apa yang terjadi di sini. Mari kita lihat apakah beberapa guru # C dapat menjelaskan di sini.
Steve
1
Jika Anda mengubah kamus pertama menjadi <string, string> and modify Points to "88" `Anda kemudian mendapatkan kesalahan kompiler" Tidak dapat secara implisit mengonversi tipe 'System.Collections.Generic.List <System.Collections.Generic.Dictionary <string, object >>' to 'string' " yang sebenarnya membantu saya mengetahui jawabannya!
pinkfloydx33
2
@OlegI Saya tidak berpikir itu bug kompiler. Banyak penjelasan bagus sudah disediakan dalam jawaban. Tetapi jika Anda coba var test = new Dictionary<string, object> { ["Name"] = "Solo", ["Points"] = 88 }["OtherAs"] = new List<Dictionary<string, object>> { new Dictionary<string, object> { ["Points"] = 1999 } };akan jelaskan lebih lanjut.
MKR

Jawaban:

54

Koma yang hilang membuat semua perbedaan. Itu menyebabkan pengindeks ["OtherAs"]diterapkan pada kamus ini:

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

Jadi intinya Anda mengatakan:

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

Perhatikan bahwa ini adalah ekspresi penugasan ( x = y). Berikut xadalah kamus dengan "Nama" dan "Poin", diindeks dengan "OtherAs"dan yadalah List<Dictionary<string, object>>. Ekspresi penugasan mengevaluasi nilai yang diberikan ( y), yang merupakan daftar kamus.

Hasil dari seluruh ekspresi ini kemudian ditugaskan ke kunci "MyA", itulah sebabnya "MyA" memiliki daftar kamus.

Anda dapat mengonfirmasi bahwa inilah yang terjadi dengan mengubah jenis kamus 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
    }
}

Ini kode Anda, tetapi diformat ulang dan beberapa tanda kurung ditambahkan untuk menggambarkan bagaimana kompiler menguraikannya:

["MyA"] 
= 
(
    (
        new Dictionary<string, object>
        {
            ["Name"] = "Solo",
            ["Points"] = 88
        }["OtherAs"] 
    )
    = 
    (
        new List<Dictionary<string, object>>
        {
            new Dictionary<string, object>
            {
                ["Points"] = 1999
            }
        }
    )
)
Penyapu
sumber
1
Hal itu mengubah kamus ini jenis nilai dari objectke stringyang memberi saya pesan kesalahan yang sama dan aha saat itu memicu jawabannya. Sepertinya Anda mengalahkan saya untuk itu - saya salah mengetik jawaban di ponsel saya :-p
pinkfloydx33
19

Apa yang terjadi di sini adalah Anda membuat kamus dan kemudian mengindeksnya. Hasil dari pengindeksan / ekspresi tugas kemudian dikembalikan dan itulah yang ditugaskan ke dalam MyAslot kamus.

Ini:

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

Dapat dibagi menjadi kode-psuedo berikut:

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

Hasil penugasan ke pengindeks kamus kedua dikembalikan (penugasan mengembalikan nilai yang ditugaskan / sisi kanan) Kamus itu adalah lokal sementara yang hanya "menghilang ke dalam eter". Hasil pengindeks (daftar kamus) adalah apa yang ditempatkan di kamus utama pada akhirnya.

Ini adalah kasus yang aneh, yang dibuat lebih mudah karena penggunaan objectsebagai jenis nilai kamus.

pinkfloydx33
sumber