2009-08-23 35 views
24

Tôi đang tìm kiếm một cách để có một chức năng như:cặp giá trị chính trong C# Params

myFunction({"Key", value}, {"Key2", value}); 

tôi chắc chắn rằng có điều gì đó với các loại vô danh đó sẽ là khá dễ dàng, nhưng tôi không nhìn thấy nó.

Giải pháp duy nhất tôi có thể nghĩ đến là phải có một "params KeyValuePair [] cặp" tham số, nhưng điều đó kết thúc lên được một cái gì đó tương tự như:

myFunction(new KeyValuePair<String, object>("Key", value), new KeyValuePair<String, object>("Key2", value)); 

Đó là, phải thừa nhận là, xấu xí hơn nhiều.

EDIT:

Để làm rõ, tôi đang viết một lớp "Tin nhắn" để chuyển giữa 2 hệ thống khác nhau. Nó chứa một ushort xác định loại tin nhắn, và một từ điển của chuỗi để đối tượng cho "dữ liệu" liên kết với tin nhắn. Tôi muốn có thể chuyển tất cả thông tin này trong nhà xây dựng, vì vậy tôi có thể thực hiện việc này:

Agent.SendMessage (Thư mới (MessageTypes.SomethingHappened, "A", x, "B", y , "C", z)); hoặc cú pháp tương tự.

+0

tôi sửa câu trả lời của tôi để bao gồm một cách hợp lý để sử dụng cú pháp điển. Hãy chắc chắn để kiểm tra xem. –

Trả lời

52

Khi cú pháp là xấu cho một mẫu khác, thay đổi cú pháp.Làm thế nào về:

public void MyFunction(params KeyValuePair<string, object>[] pairs) 
{ 
    // ... 
} 

public static class Pairing 
{ 
    public static KeyValuePair<string, object> Of(string key, object value) 
    { 
     return new KeyValuePair<string, object>(key, value); 
    } 
} 

Cách sử dụng:

MyFunction(Pairing.Of("Key1", 5), Pairing.Of("Key2", someObject)); 

Ngay cả chi tiết thú vị sẽ có thêm một phương pháp khuyến nông để string để làm cho nó pairable:

public static KeyValuePair<string, object> PairedWith(this string key, object value) 
{ 
    return new KeyValuePair<string, object>(key, value); 
} 

Cách sử dụng:

MyFunction("Key1".PairedWith(5), "Key2".PairedWith(someObject)); 

Sửa: Bạn cũng có thể sử dụng cú pháp điển không có dấu ngoặc chung bằng cách bắt nguồn từ Dictionary<,>:

public void MyFunction(MessageArgs args) 
{ 
    // ... 
} 

public class MessageArgs : Dictionary<string, object> 
{} 

Cách sử dụng:

MyFunction(new MessageArgs { { "Key1", 5 }, { "Key2", someObject } }); 
+0

Hmm, đây là một giải pháp thông minh, tôi thích nó. Tôi nghĩ rằng đây là những gì tôi sẽ sử dụng. Cảm ơn bạn. Tôi sẽ để lại câu hỏi chưa được trả lời trong một hoặc hai giờ để xem liệu có giải pháp nào khác được đưa ra hay không. – Quantumplation

+0

Hoặc bạn có thể đi đường boxing và làm 'MyFunction (params object [] args)' –

2

Sử dụng một từ điển:

myFunction(new Dictionary<string, object>(){ 
    {"Key", value}, 
    {"Key2", value}}); 

Đó là thẳng về phía trước, bạn chỉ có một new Dictionary<K, V> cần, chứ không phải cho mỗi đối số. Đó là tầm thường để có được các phím và giá trị.

Hoặc với một loại vô danh:

myFunction(new { 
    Key = value, 
    Key2 = value}); 

Đó là không phải là rất tốt đẹp để sử dụng bên trong hàm, bạn sẽ cần phải suy nghĩ. Điều này sẽ giống như thế này:

foreach (PropertyInfo property in arg.GetType().GetProperties()) 
{ 
    key = property.Name; 
    value = property.GetValue(arg, null); 
} 

(staight từ đầu tôi, có lẽ một số lỗi ...)

+0

Làm cách nào để vẽ các cặp khóa/giá trị ra khỏi loại thứ hai? – Quantumplation

+0

Bạn tìm số thứ hai trong phương thức ActionLink trong asp.net MVC. Điều này có cần phản ánh để có được tên và giá trị của thuộc tính không? –

2

Sử dụng một Dictionary ...

void Main() 
{ 
    var dic = new Dictionary<string, object>(); 
    dic.Add("Key1", 1); 
    dic.Add("Key2", 2); 

    MyFunction(dic).Dump(); 
} 

public static object MyFunction(IDictionary dic) 
{ 
    return dic["Key1"]; 
} 
+1

Vâng vâng, nhưng việc gọi hàm ở đây phức tạp bởi yêu cầu khai báo từ điển trước. Ngoài ra, cái gì là .Dump() cho? – Quantumplation

+0

Rất tiếc, Dump là từ LINQPad, chỉ cần nghĩ Console.Writeline. Tại sao bạn sẽ mâu thuẫn với chính mình để có mọi thứ trong một tuyên bố? Bạn nên làm cho giao diện của bạn chính xác. Lo lắng về quy ước gọi điện thoại sẽ là một giây xa xôi. –

+2

Nó dành cho các nhà xây dựng của một lớp Message, một cái gì đó được gửi khá thường xuyên, và một quy ước gọi điện khó sử dụng sẽ đi theo con đường sau này. phải khai báo từ điển, thêm khóa và truyền nó cho hàm tạo cho nhiều trường hợp khác nhau khi thư được gửi trở nên khó chịu, và làm sao lãng trình đọc/ghi chú khỏi những gì đang diễn ra, và do đó trở nên khó duy trì hơn. – Quantumplation

2

Dưới đây là nhiều hơn trong cùng:

static void Main(string[] args) 
{ 
    // http://msdn.microsoft.com/en-us/library/bb531208.aspx 
    MyMethod(new Dictionary<string,string>() 
    { 
     {"key1","value1"}, 
     {"key2","value2"} 
    }); 
} 

static void MyMethod(Dictionary<string, string> dictionary) 
{ 
    foreach (string key in dictionary.Keys) 
    { 
     Console.WriteLine("{0} - {1}", key, dictionary[key]); 
    } 
} 

Một số chi tiết về khởi tạo từ điển có thể được tìm thấy here.

7

Một chút của một hack, nhưng bạn có thể có lớp Message của bạn triển khai giao diện IEnumerable và cung cấp phương thức Add. Sau đó bạn sẽ có thể sử dụng cú pháp thu initializer:

Agent.SendMessage 
(
    new Message(MessageTypes.SomethingHappened) {{ "foo", 42 }, { "bar", 123 }} 
); 

// ... 

public class Message : IEnumerable 
{ 
    private Dictionary<string, object> _map = new Dictionary<string, object>(); 

    public Message(MessageTypes mt) 
    { 
     // ... 
    } 

    public void Add(string key, object value) 
    { 
     _map.Add(key, value); 
    } 

    IEnumerator IEnumerable.GetEnumerator() 
    { 
     return ((IEnumerable)_map).GetEnumerator(); 
     // or throw a NotImplementedException if you prefer 
    } 
} 
+0

Điều này dường như có chi phí thấp hơn nhiều so với phương pháp Reflection, và thực sự có thể không phải là hack, vì tôi muốn có thêm chức năng Mọi tình huống. – Quantumplation

+1

Tùy thuộc vào số lượng bạn muốn lớp 'Message' hoạt động giống như một bộ sưu tập thực, bạn có thể thực hiện giao diện" lớn hơn "thay vì 'IEnumerable' thay thế (ví dụ:' IDictionary '). Tôi chỉ chọn 'IEnumerable' vì nó cho phép cú pháp khởi tạo bộ sưu tập với số lượng công việc phụ tối thiểu! – LukeH

7

Funny, tôi vừa tạo (phút trước) một phương pháp cho phép để làm điều đó, sử dụng các loại vô danh và phản ánh:

MyMethod(new { Key1 = "value1", Key2 = "value2" }); 


public void MyMethod(object keyValuePairs) 
{ 
    var dic = DictionaryFromAnonymousObject(keyValuePairs); 
    // Do something with the dictionary 
} 

public static IDictionary<string, string> DictionaryFromAnonymousObject(object o) 
{ 
    IDictionary<string, string> dic = new Dictionary<string, string>(); 
    var properties = o.GetType().GetProperties(); 
    foreach (PropertyInfo prop in properties) 
    { 
     dic.Add(prop.Name, prop.GetValue(o, null) as string); 
    } 
    return dic; 
} 
+0

Hoàn hảo! Đây chỉ là loại giải pháp mà tôi đang tìm kiếm. Bao nhiêu chi phí là có vì sự phản ánh? – Quantumplation

+0

Không có ý tưởng ... Dù sao, giải pháp này là tiện dụng, nhưng không phù hợp nếu hiệu suất là rất quan trọng cho ứng dụng của bạn –

1

bạn có thể làm điều đó:

TestNamedMethod(DateField => DateTime.Now, IdField => 3); 

nơi DateField IdField được coi là một 'chuỗi' identif iers.

Các TestNameMethod:

public static string TestNameMethod(params Func<object, object>[] args) 
{ 
    var name = (args[0].Method.GetParameters()[0]).Name; 
    var val = args[0].Invoke(null); 
    var name2 = (args[1].Method.GetParameters()[0]).Name; 
    var val2 = args[1].Invoke(null); 
    Console.WriteLine("{0} : {1}, {2} : {3}", name, val, name2, val2); 
} 

Hiệu suất là nhanh hơn so với sử dụng từ điển 5%. Nhược điểm: bạn không thể sử dụng biến làm khóa.

2

Với loại động trong C# 4.0:

public class MyClass 
{ 
    // Could use another generic type if preferred 
    private readonly Dictionary<string, dynamic> _dictionary = new Dictionary<string, dynamic>(); 

    public void MyFunction(params dynamic[] kvps) 
    { 
     foreach (dynamic kvp in kvps) 
      _dictionary.Add(kvp.Key, kvp.Value); 
    } 
} 

Gọi sử dụng:

MyFunction(new {Key = "Key1", Value = "Value1"}, new {Key = "Key2", Value = "Value2"}); 
0

Bạn có thể sử dụng Tuples để đạt được một cái gì đó tương tự như @Bryan Watts của Pairing.Of mà không học thêm:

public static void MyFunction(params Tuple<string, int>[] pairs) 
{ 
} 

MyFunction(Tuple.Create("foo", 1), Tuple.Create("bar", 2)); 
0

Bạn cũng có thể tham khảo nugetpackage "valuetuple", cho phép bạn làm như sau:

public static void MyFunction(params ValueTuple<string, object>[] pairs) 
{ 
    var pair = pairs[1]; 
    var stringValue = pair.item1; 
    var objectValue = pair.item2; 
} 

Sau đó bạn có thể gọi phương thức như thế này:

MyFunction(("string",object),("string", object)); 
1

Kể từ C# 7.0, bạn có thể sử dụng các bộ giá trị. C# 7.0 không chỉ giới thiệu một kiểu mới mà là một cú pháp đơn giản mới cho các bộ dữ liệu.

public static void MyFunction(params (string Key, object Value)[] pairs) 
{ 
    foreach (var pair in pairs) { 
     Console.WriteLine($"{pair.Key} = {pair.Value}"); 
    } 
} 

Nó cũng có thể mổ xẻ một tuple như thế này

 var (key, value) = pair; 
     Console.WriteLine($"{key} = {value}"); 

này chiết xuất các mặt hàng của tuple trong hai biến riêng biệt keyvalue.

Bây giờ bạn có thể gọi chức năng này như thế này với một số thay đổi của đối số:

MyFunction(("a", 1), ("b", 2), ("c", 3)); 

Xem: New Features in C# 7.0

Các vấn đề liên quan