Key value pairs in C# Params

2019-03-22 15:07发布

I'm looking for a way to have a function such as:

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

I'm sure there's something with anonymous types that would be pretty easy, but I'm not seeing it.

The only solution I can think of is to have a "params KeyValuePair[] pairs" parameter, but that ends up being something similar to:

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

Which is, admittedly, much uglier.

EDIT:

To clarify, I'm writing a "Message" class to pass between 2 different systems. It contains a ushort specifying the the Message Type, and a dictionary of string to object for "Data" associated with the message. I'd like to be able to pass all this information in the constructor, so I am able to do this:

Agent.SendMessage(new Message(MessageTypes.SomethingHappened, "A", x, "B", y, "C", z)); or similar syntax.

11条回答
干净又极端
2楼-- · 2019-03-22 15:25

Using a dictionary:

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

Which is straight forward, you need only one new Dictionary<K, V>, not for each argument. It's trivial to get the keys and values.

Or with an anonymous type:

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

Which is not very nice to use inside the function, you'll need reflection. This would look something like this:

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

(Staight from my head, probably some errors...)

查看更多
手持菜刀,她持情操
3楼-- · 2019-03-22 15:30

With dynamic type in 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);
    }
}

Call using:

MyFunction(new {Key = "Key1", Value = "Value1"}, new {Key = "Key2", Value = "Value2"});
查看更多
【Aperson】
4楼-- · 2019-03-22 15:34

Since C# 7.0, you can use value tuples. C# 7.0 not only introduces a new type but a simplified syntax for tuple types as well as for tuple values.

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

It is also possible to deconstruct a tuple like this

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

This extracts the items of the tuple in two separate variables key and value.

Now, you can call MyFunction with a varying number of arguments easily:

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

See: New Features in C# 7.0

查看更多
We Are One
5楼-- · 2019-03-22 15:37

When the syntax is bad for an otherwise decent pattern, change the syntax. How about:

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

Usage:

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

Even more interesting would be to add an extension method to string to make it pairable:

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

Usage:

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

Edit: You can also use the dictionary syntax without the generic brackets by deriving from Dictionary<,>:

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

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

Usage:

MyFunction(new MessageArgs { { "Key1", 5 }, { "Key2", someObject } });
查看更多
够拽才男人
6楼-- · 2019-03-22 15:37

Funny, I just created (minutes ago) a method that allows to do that, using anonymous types and reflection :

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;
}
查看更多
爱情/是我丢掉的垃圾
7楼-- · 2019-03-22 15:37

Use a 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"];
}
查看更多
登录 后发表回答