สัญกรณ์ตามตัวอักษรสำหรับพจนานุกรมใน C #?


182

ขณะนี้ฉันมี WebSocket ระหว่าง JavaScript และเซิร์ฟเวอร์ที่ตั้งโปรแกรมใน C # ใน JavaScript ฉันสามารถส่งผ่านข้อมูลได้อย่างง่ายดายโดยใช้อาเรย์แบบเชื่อมโยง:

var data = {'test': 'val',
            'test2': 'val2'};

เพื่อเป็นตัวแทนวัตถุข้อมูลนี้ในฝั่งเซิร์ฟเวอร์ฉันใช้ a Dictionary<string, string>แต่มัน 'พิมพ์แพงกว่าใน JavaScript:

Dictionary<string, string> data = new Dictionary<string,string>();
data.Add("test", "val");
data.Add("test2", "val2");

มีสัญกรณ์ตามตัวอักษรสำหรับอาร์เรย์ที่เชื่อมโยง / Dictionarys ใน C # หรือไม่?


C # 9 มีข้อเสนอสำหรับพจนานุกรมตัวอักษร ฉันโพสต์คำตอบเกี่ยวกับเรื่องดังต่อไปนี้ ความฝันของเราเป็นจริง!
aloisdg ย้ายไปยัง codidact.com

คำตอบ:


291

คุณใช้ไวยากรณ์เริ่มต้นของคอลเลกชันแต่คุณยังต้องทำให้new Dictionary<string, string>วัตถุเป็นอันดับแรกเนื่องจากมีการแปลไวยากรณ์ทางลัดเป็นกลุ่มของการAdd()โทร (เช่นรหัสของคุณ):

var data = new Dictionary<string, string>
{
    { "test", "val" }, 
    { "test2", "val2" }
};

ใน C # 6 ตอนนี้คุณมีตัวเลือกของการใช้ไวยากรณ์ที่ใช้งานง่ายมากขึ้นด้วยพจนานุกรมเช่นเดียวกับชนิดอื่น ๆ ที่สนับสนุนindexers ข้อความข้างต้นสามารถเขียนใหม่ได้เป็น:

var data = new Dictionary<string, string>
{
    ["test"] = "val",
    ["test2"] = "val2"
};

ซึ่งแตกต่างจากการเริ่มต้นคอลเลกชันนี้จะเรียกตัวสร้างดัชนีภายใต้ประทุนมากกว่าAdd()วิธีที่เหมาะสม


2
ขอบคุณ มันเป็นไปได้ที่จะเอาหนึ่งในDictionary<string, string>ว่า? ดูเหมือนจะค่อนข้างซ้ำซ้อน แต่ฉันอาจผิด แก้ไข: ดูเหมือนว่าเป็นวิธีที่ดีกว่านี้แน่นอนขอบคุณ
pimvdb

3
@pimvdb: Yup คุณสามารถ: ประกาศว่ามันเป็นคอมไพเลอร์จะอนุมานชนิดจากที่var newฉันแก้ไขคำตอบของฉัน
BoltClock

7
โปรดทราบว่ามันไม่ใช่สัญกรณ์ที่แท้จริงพูดอย่างเคร่งครัด ... มันเป็นเพียงทางลัดสำหรับการเริ่มต้น เฉพาะสตริงและบางประเภทดั้งเดิมเท่านั้นที่มีตัวอักษร
โทมัสเลเวส

หากคุณหมายถึงคุณต้องการลบหนึ่งใน "สตริง" s - พวกเขาจะไม่ซ้ำซ้อน - หนึ่งคือสำหรับประเภทคีย์อื่น ๆ สำหรับประเภทค่า ไม่มีตัวอักษรที่เฉพาะเจาะจงสำหรับพจนานุกรมสัญกรณ์ที่ใช้ในคำตอบนี้เป็นเรื่องทั่วไปสำหรับทุกชั้นเรียนที่มีวิธีการเพิ่มที่ใช้สองสาย (และดำเนินการ IEnumerable)
Markus Johnsson

1
@ Markus Johnsson: เขาหมายถึงอย่างแท้จริง, Dictionary<string, string>. ตอนแรกรหัสของฉันประกาศประเภทฉันเพิ่งเปลี่ยนเป็นvarหลังจากความคิดเห็นของเขา
BoltClock

13

ในขณะที่คำตอบตัวเริ่มต้นพจนานุกรมถูกต้องทั้งหมดมีอีกวิธีหนึ่งที่ฉันจะชี้ให้เห็น (แต่ฉันอาจไม่แนะนำ) หากเป้าหมายของคุณคือให้การใช้งาน API สั้น ๆ คุณสามารถใช้วัตถุที่ไม่ระบุชื่อได้

var data = new { test1 = "val", test2 = "val2"};

"ข้อมูล" ตัวแปรแล้วของ "พูดไม่ได้" System.Objectชนิดที่ไม่ระบุชื่อเพื่อให้คุณสามารถผ่านรอบนี้เป็น จากนั้นคุณสามารถเขียนรหัสที่สามารถแปลงวัตถุที่ไม่ระบุชื่อเป็นพจนานุกรม รหัสดังกล่าวจะขึ้นอยู่กับการสะท้อนซึ่งอาจจะช้า อย่างไรก็ตามคุณสามารถใช้System.Reflection.EmitหรือSystem.Linq.Expressionsเพื่อคอมไพล์และแคชผู้รับมอบสิทธิ์ที่จะทำให้การโทรในภายหลังนั้นเร็วขึ้น

Asp.net MVC API ใช้เทคนิคนี้ในหลาย ๆ ที่ที่ฉันเคยเห็น ผู้ช่วย Html จำนวนมากมีภาระมากเกินไปที่ยอมรับวัตถุหรือพจนานุกรม ฉันถือว่าเป้าหมายของการออกแบบ API ของพวกเขาเหมือนกับที่คุณทำ ไวยากรณ์ของคำศัพท์สั้น ๆ ที่การเรียกใช้เมธอด


1
นั่นจะช่วยได้ก็ต่อเมื่อชุดของปุ่มคงที่ คุณยังสามารถใช้ Tuples เพื่อจุดประสงค์เดียวกัน
sehe

8

การใช้DynamicObjectไม่ใช่เรื่องยากที่จะสร้างเครื่องมือเริ่มต้นพจนานุกรมที่ง่ายขึ้น

ลองนึกภาพคุณต้องการเรียกวิธีการต่อไปนี้

void PrintDict(IDictionary<string, object> dict) {
    foreach(var kv in dict) {
        Console.WriteLine ("  -> " + kv.Key + " = " + kv.Value);
    }
}

ใช้ไวยากรณ์ตัวอักษรเช่น

var dict = Dict (Hello: "World", IAm: "a dictionary");
PrintDict (dict);

สามารถทำได้โดยการสร้างวัตถุแบบไดนามิกเช่นนี้

dynamic Dict {
    get {
        return new DynamicDictFactory ();
    }
}

private class DynamicDictFactory : DynamicObject
{
    public override bool TryInvoke (InvokeBinder binder, object[] args, out object result)
    {
        var res = new Dictionary<string, object> ();
        var names = binder.CallInfo.ArgumentNames;

        for (var i = 0; i < args.Length; i++) {
            var argName = names [i];
            if(string.IsNullOrEmpty(argName)) throw new ArgumentException();
            res [argName] = args [i];
        }
        result = res;
        return true;
    }
}

6

ใช้ตัวอักษรพจนานุกรม (ข้อเสนอ C # 9)

C # 9 แนะนำไวยากรณ์ที่ง่ายขึ้นในการสร้างDictionary<TKey,TValue>วัตถุเริ่มต้นโดยไม่ต้องระบุชื่อประเภทพจนานุกรมหรือพารามิเตอร์ประเภท พารามิเตอร์ชนิดสำหรับพจนานุกรมถูกอนุมานโดยใช้กฎที่มีอยู่ซึ่งใช้สำหรับการอนุมานประเภทอาร์เรย์

// C# 1..8    
var x = new Dictionary <string,int> () { { "foo", 4 }, { "bar", 5 }};   
// C# 9    
var x = ["foo":4, "bar": 5];  

synthax นี้ทำให้การทำงานกับพจนานุกรมใน C # ง่ายขึ้นและลบรหัสซ้ำซ้อน

คุณสามารถติดตามปัญหาในGitHub (และนี่คือเหตุการณ์สำคัญสำหรับ C # 9 )

แก้ไข: ข้อเสนอนี้ถูกปฏิเสธในขณะนี้:

[... ] เราคิดว่ามีหลายกรณีการใช้งานที่น่าสนใจเกี่ยวกับการเริ่มต้นข้อมูลโดยเฉพาะอย่างยิ่งสำหรับสิ่งต่าง ๆ เช่นพจนานุกรมไม่เปลี่ยนรูป เราไม่พบไวยากรณ์ที่มีอยู่สำหรับการเริ่มต้นพจนานุกรมที่เป็นภาระและเราไม่เห็นว่าเป็นรูปแบบบ่อยครั้งในรหัสที่จะได้รับประโยชน์มากจากคุณลักษณะภาษา สิ่งที่เราควรตรวจสอบพื้นที่ทั่วไปของการเริ่มต้นข้อมูลอีกครั้งหลังจากที่เราบันทึกและเหี่ยวเฉา [ ... ]


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