Ký hiệu nghĩa đen cho từ điển trong C #?


181

Tôi hiện có một WebSocket giữa JavaScript và một máy chủ được lập trình bằng C #. Trong JavaScript, tôi có thể truyền dữ liệu dễ dàng bằng cách sử dụng một mảng kết hợp:

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

Để thể hiện đối tượng dữ liệu này ở phía máy chủ, tôi sử dụng một Dictionary<string, string>, nhưng điều này là 'tốn kém hơn' so với JavaScript:

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

Có một số loại ký hiệu theo nghĩa đen cho các mảng / Dictionarys liên kết trong C #?


C # 9 chứa một đề xuất cho Từ điển văn học. Tôi gửi một câu trả lời về nó dưới đây . Ước mơ của chúng tôi trở thành sự thật!
aloisdg chuyển đến codidact.com

Câu trả lời:


291

Bạn sử dụng cú pháp bộ khởi tạo bộ sưu tập , nhưng trước tiên bạn vẫn cần tạo một new Dictionary<string, string>đối tượng vì cú pháp phím tắt được dịch thành một loạt các Add()cuộc gọi (như mã của bạn):

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

Trong C # 6, giờ đây bạn có tùy chọn sử dụng cú pháp trực quan hơn với Từ điển cũng như bất kỳ loại nào khác hỗ trợ bộ chỉ mục . Tuyên bố trên có thể được viết lại thành:

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

Không giống như bộ khởi tạo bộ sưu tập, cái này gọi trình thiết lập bộ chỉ mục dưới mui xe, thay vì một Add()phương thức thích hợp .


2
Cảm ơn. Có thể loại bỏ một trong những Dictionary<string, string>mặc dù? Có vẻ khá dư thừa, nhưng tôi có thể sai. Chỉnh sửa: Đây có vẻ là một cách tốt hơn thực sự, cảm ơn bạn.
pimvdb

3
@pimvdb: Yup bạn có thể: khai báo nó là a var, trình biên dịch sẽ suy ra kiểu từ new. Tôi chỉnh sửa câu trả lời của tôi.
BoltClock

7
Lưu ý rằng đó không phải là ký hiệu theo nghĩa đen, nói đúng ra ... nó chỉ là một lối tắt để khởi tạo. Chỉ có chuỗi và một số loại nguyên thủy có đại diện theo nghĩa đen
Thomas Levesque

Nếu bạn có nghĩa là bạn muốn xóa một trong các "chuỗi" - chúng không dư thừa - một là cho loại khóa, cái còn lại là loại giá trị. Không có nghĩa đen cụ thể cho Từ điển, ký hiệu được sử dụng trong câu trả lời này là chung cho tất cả các lớp với phương thức Add có hai chuỗi (và thực hiện IEnumerable).
Markus Johnsson

1
@Markus Johnsson: Ý anh là, theo nghĩa đen , Dictionary<string, string>. Mã của tôi ban đầu đã khai báo loại, tôi vừa đổi nó thành varsau nhận xét của anh ấy.
BoltClock

13

Trong khi, câu trả lời của trình khởi tạo từ điển là hoàn toàn chính xác, có một cách tiếp cận khác mà tôi muốn chỉ ra (nhưng tôi có thể không khuyến nghị nó). Nếu mục tiêu của bạn là cung cấp việc sử dụng API ngắn gọn, bạn có thể sử dụng các đối tượng ẩn danh.

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

Biến "dữ liệu" sau đó thuộc loại ẩn danh "không thể nói rõ", vì vậy bạn chỉ có thể vượt qua điều này như là System.Object. Sau đó, bạn có thể viết mã có thể chuyển đổi một đối tượng ẩn danh thành một từ điển. Mã như vậy sẽ dựa vào sự phản ánh, có khả năng sẽ chậm. Tuy nhiên, bạn có thể sử dụng System.Reflection.Emithoặc System.Linq.Expressionsbiên dịch và lưu trữ một đại biểu để thực hiện các cuộc gọi tiếp theo nhanh hơn nhiều.

API MVC Asp.net sử dụng kỹ thuật này ở một số nơi tôi đã thấy. Rất nhiều Trình trợ giúp Html có tình trạng quá tải chấp nhận một đối tượng hoặc từ điển. Tôi cho rằng mục tiêu thiết kế API của họ giống như những gì bạn đang theo đuổi; cú pháp terse tại cuộc gọi phương thức.


1
Điều đó sẽ chỉ có ích khi bộ khóa là tĩnh. Bạn cũng có thể sử dụng Tuples cho cùng một mục đích.
sehe

8

Sử dụng DynamicObject, không khó để tạo một trình khởi tạo từ điển đơn giản hơn.

Hãy tưởng tượng bạn muốn gọi phương thức sau

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

sử dụng một cú pháp theo nghĩa đen như

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

Điều này có thể được thực hiện bằng cách tạo một đối tượng động như thế này

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

Sử dụng từ điển văn học (đề xuất C # 9)

C # 9 giới thiệu một cú pháp đơn giản hơn để tạo Dictionary<TKey,TValue>các đối tượng khởi tạo mà không phải chỉ định tên loại Từ điển hoặc tham số loại. Các tham số loại cho từ điển được suy ra bằng cách sử dụng các quy tắc hiện có được sử dụng cho suy luận kiểu mảng.

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

Synthax này làm cho công việc với các từ điển trong C # đơn giản hơn và loại bỏ mã dự phòng.

Bạn có thể theo dõi vấn đề trên GitHub (và đây là cột mốc cho C # 9 ).

Chỉnh sửa: Đề xuất này hiện đang bị từ chối :

[...] Chúng tôi nghĩ rằng có một số trường hợp sử dụng thú vị xung quanh việc khởi tạo dữ liệu, đặc biệt đối với những thứ như từ điển bất biến. Chúng tôi không tìm thấy cú pháp hiện có để khởi tạo một từ điển gây khó chịu, chúng tôi cũng không xem đó là một mẫu thường xuyên trong mã sẽ có lợi nhiều từ tính năng ngôn ngữ. Chúng tôi cho rằng khu vực chung của việc khởi tạo dữ liệu nên được xem xét lại sau khi chúng tôi thực hiện các bản ghi và héo. [...]


1
Ý tưởng tuyệt vời, hy vọng nó làm cho nó vào, có vẻ như không có trí tuệ
jjxtra
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.