การเริ่มต้นพจนานุกรม C # นี้ถูกต้องอย่างไร


64

ฉันสะดุดต่อไปนี้และฉันสงสัยว่าทำไมมันไม่ทำให้เกิดข้อผิดพลาดทางไวยากรณ์

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

โปรดสังเกตว่า "," ขาดหายไประหว่าง "MyA" และ "OtherAs"

นี่คือสิ่งที่เกิดความสับสน:

  1. รหัสรวบรวม
  2. พจนานุกรมสุดท้าย "dict" มีเพียงสามองค์ประกอบ: "Id", "Tribes" และ "MyA"
  3. ค่าทั้งหมดยกเว้น "MyA" ถูกต้อง
  4. "MyA" รับค่าที่ประกาศสำหรับ "OtherAs" ในขณะที่ค่าดั้งเดิมจะถูกละเว้น

ทำไมจึงไม่ผิดกฎหมาย นี่เป็นการออกแบบหรือเปล่า?


1
@ Steve นั่นคือสิ่งที่เขาถาม ฉันวางนี้ลงใน sharplab และดูเหมือนว่าในตอนแรกOtherAsได้รับเพิ่มเป็นสำคัญในสิ่งที่จะเป็นMyAพจนานุกรม (ชื่อ = Solo จุด = 88 บวก OtherAs = รายการ <พจนานุกรม <สตริงวัตถุ >>) ยกเว้นมันก็ไม่เคยกำหนดว่ามัน แต่จะวางรายการของ dicts ตอนนี้มีเพียงรายการ Points = 1999 เดียวในMyAช่องที่แทนที่สิ่งที่ใครคิดว่ามีอยู่
pinkfloydx33

1
ลิงก์ยาวเกินไปที่จะวางในความคิดเห็นแรก นี่มันแปลกจริงๆ sharplab.io/…
pinkfloydx33

1
ใช่ฉันได้ทดสอบกับ LinqPad และได้ผลลัพธ์เดียวกัน ไม่แน่ใจว่าเกิดอะไรขึ้นที่นี่ ลองดูว่ากูรู C # บางคนสามารถส่องแสงที่นี่ได้ไหม
Steve

1
หากคุณเปลี่ยนพจนานุกรมแรกเป็น<string, string> and modify Points to "88" `คุณจะได้รับข้อผิดพลาดของคอมไพเลอร์" ไม่สามารถแปลงประเภท 'System.Collections.Generic.List <System.Collections.Generic.Dictionary <string, object >>' เป็น 'string' "โดยปริยาย ซึ่งจริง ๆ แล้วช่วยฉันหาคำตอบ!
pinkfloydx33

2
@OlegI ฉันไม่คิดว่ามันเป็นข้อผิดพลาดของคอมไพเลอร์ คำอธิบายที่ดีมากมายให้คำตอบแล้ว แต่ถ้าลองแล้วvar test = new Dictionary<string, object> { ["Name"] = "Solo", ["Points"] = 88 }["OtherAs"] = new List<Dictionary<string, object>> { new Dictionary<string, object> { ["Points"] = 1999 } };จะอธิบายให้ฟังต่อไป
MKR

คำตอบ:


54

เครื่องหมายจุลภาคที่หายไปสร้างความแตกต่าง ทำให้ดัชนี["OtherAs"]ที่จะใช้กับพจนานุกรมนี้:

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

ดังนั้นโดยพื้นฐานแล้วคุณกำลังพูดว่า:

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

โปรดทราบว่านี่คือการแสดงออกที่ได้รับมอบหมาย ( x = y) นี่xเป็นพจนานุกรมที่มี "ชื่อ" และ "จุด" การจัดทำดัชนี"OtherAs"และเป็นy List<Dictionary<string, object>>การแสดงออกที่ได้รับมอบหมายประเมินค่าที่ได้รับมอบหมาย ( y) ซึ่งเป็นรายการของพจนานุกรม

ผลลัพธ์ของนิพจน์ทั้งหมดนี้จะถูกกำหนดให้กับคีย์ "MyA" ซึ่งเป็นสาเหตุที่ "MyA" มีรายการพจนานุกรม

คุณสามารถยืนยันได้ว่านี่คือสิ่งที่เกิดขึ้นโดยการเปลี่ยนประเภทของพจนานุกรม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
    }
}

นี่คือรหัสของคุณ แต่มีการจัดรูปแบบใหม่และมีการเพิ่มวงเล็บในตัวอย่างที่คอมไพเลอร์แยกวิเคราะห์:

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

1
มันเป็นการเปลี่ยนประเภทของค่าพจนานุกรมจากobjectเป็นstringทำให้เกิดข้อผิดพลาดที่คล้ายกันและช่วงเวลาahaที่จุดประกายคำตอบ ดูเหมือนว่าคุณจะชนะฉัน - ฉันโทษคำตอบที่พิมพ์บนโทรศัพท์ของฉัน :-p
pinkfloydx33

19

สิ่งที่เกิดขึ้นที่นี่คือคุณกำลังสร้างพจนานุกรมและจัดทำดัชนีไว้ ผลลัพธ์ของนิพจน์ตัวทำดัชนี / การกำหนดจะถูกส่งคืนและนั่นคือสิ่งที่จะถูกกำหนดลงในMyAสล็อตพจนานุกรม

นี้:

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

สามารถแบ่งออกเป็นรหัส psuedo ต่อไปนี้:

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

ผลลัพธ์ของการกำหนดให้กับตัวสร้างดัชนีของพจนานุกรมที่สองจะถูกส่งกลับ (การกำหนดส่งคืนค่าที่กำหนด / ด้านขวามือ) พจนานุกรมนั้นเป็นพื้นที่ชั่วคราวที่เพิ่งจะ "หายเข้าไปในอีเธอร์" ผลลัพธ์ของตัวทำดัชนี (รายการพจนานุกรม) คือสิ่งที่วางไว้ในพจนานุกรมหลักในที่สุด

นี่เป็นกรณีแปลก ๆ ซึ่งทำให้ง่ายต่อการตกหล่นเนื่องจากการใช้objectเป็นชนิดของค่าพจนานุกรม

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.