C# 参数中的键值对

发布于 2024-08-02 05:36:01 字数 694 浏览 8 评论 0原文

我正在寻找一种方法来实现这样的功能:

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

我确信有一些带有匿名类型的东西会非常简单,但我没有看到它。

我能想到的唯一解决方案是使用 params KeyValuePair[]pairs 参数,但最终结果类似于:

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

不可否认,这要丑陋得多。

编辑:

为了澄清,我正在编写一个 Message 类来在两个不同的系统之间传递。它包含一个指定消息类型的ushort,以及一个用于与消息关联的“数据”对象的字符串字典。我希望能够在构造函数中传递所有这些信息,因此我能够执行以下操作:

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

或类似的语法。

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<String, object>[] 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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(12

半仙 2024-08-09 05:36:01

当语法对于原本不错的模式来说很糟糕时,请更改语法。怎么样:

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

用法:

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

更有趣的是向 string 添加扩展方法以使其可配对:

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

用法:

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

编辑:您还可以使用字典语法而不使用泛型括号由 Dictionary<,> 派生而来:

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

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

用法:

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

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 } });
美人如玉 2024-08-09 05:36:01

从 C# 7.0 开始,您可以使用值元组。 C# 7.0 不仅引入了新类型,还引入了元组类型和元组值的简化语法。元组类型简单地写为用大括号括起来的类型列表:

(string, int, double)

相应的元素名为 Item1Item2Item3。您还可以指定可选的别名。这些别名只是语法糖(C# 编译器的一个技巧);元组仍然基于不变式(但通用)System.ValueTuple 结构

(string name, int count, double magnitude)

元组值具有类似的语法,只不过您指定表达式而不是类型

("test", 7, x + 5.91)

或使用别名

(name: "test", count: 7, magnitude: x + 5.91)

使用 params 数组的示例:

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

也可以像这样解构元组

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

您可以解构 foreach 中的循环变量:

foreach (var (key, value) in pairs) {
    Console.WriteLine($"{key} = {value}");
}

这会在两个单独的变量 keyvalue 中提取元组的项目。

现在,您可以使用不同数量的参数轻松调用 MyFunction

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

它允许我们做类似的事情,

DrawLine((0, 0), (10, 0), (10, 10), (0, 10), (0, 0));

请参阅: C# 7.0 中的新功能

Since C# 7.0, you can use value tuples. C# 7.0 not only introduces new types but a simplified syntax for tuple types and for tuple values. A tuple type is simply written as a list of types surrounded by braces:

(string, int, double)

The corresponding elements are named Item1, Item2, Item3. You can also specify optional aliases. These aliases are only syntactic sugar (a trick of the C# compiler); the tuples are still based on the invariant (but generic) System.ValueTuple<T1, T2, ...> struct.

(string name, int count, double magnitude)

Tuple values have a similar syntax, except that you specify expressions instead of types

("test", 7, x + 5.91)

or with the aliases

(name: "test", count: 7, magnitude: x + 5.91)

Example with params array:

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

It is also possible to deconstruct a tuple like this

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

You can deconstruct the loop variables in the foreach:

foreach (var (key, value) in pairs) {
    Console.WriteLine(
quot;{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));

It allows us to do things like

DrawLine((0, 0), (10, 0), (10, 10), (0, 10), (0, 0));

See: New Features in C# 7.0

千仐 2024-08-09 05:36:01

有趣的是,我刚刚创建了(几分钟前)一个允许使用匿名类型和反射来做到这一点的方法:

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

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;
}
清晰传感 2024-08-09 05:36:01

有点黑客,但您可以让您的 Message 类实现 IEnumerable 接口并为其提供一个 Add 方法。然后,您将能够使用集合初始值设定项语法:

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

A bit of a hack, but you could have your Message class implement the IEnumerable interface and give it an Add method. You'll then be able to use collection initializer syntax:

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
    }
}
握住你手 2024-08-09 05:36:01

使用字典:

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

这很简单,您只需要一个新字典,而不是每个参数。获取键和值很简单。

或者使用匿名类型:

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

这在函数内部使用不太好,您需要反射。这看起来像这样:(

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

直接从我的脑海中,可能有一些错误......)

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...)

神魇的王 2024-08-09 05:36:01

使用 字典 ...

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

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"];
}
情深如许 2024-08-09 05:36:01

更多相同内容:

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

可以在此处找到有关初始化字典的一些详细信息。

Here's more of the same:

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

Some details on initialising a dictionary can be found here.

谈场末日恋爱 2024-08-09 05:36:01

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

调用使用:

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

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"});
就像说晚安 2024-08-09 05:36:01

您还可以引用 nugetpackage“valuetuple”,它允许您执行以下操作:

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

然后您可以像这样调用该方法:

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

You could also reference the nugetpackage "valuetuple", which allows you to do the following:

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

You can then call the method like this:

MyFunction(("string",object),("string", object));
人│生佛魔见 2024-08-09 05:36:01

您可以这样做:

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

其中 DateFieldIdField 应该是“字符串”标识符。

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

性能比使用字典快 5%。缺点:不能使用变量作为键。

You can do that:

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

where DateField and IdField are supposed to be a 'string' identifiers.

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

Performance is 5% faster than using Dictionary. Disadvantage: you can't use variable as a key.

屌丝范 2024-08-09 05:36:01

您可以使用元组来实现类似于 @Bryan Watts 的 Pairing.Of 的功能,而无需额外的类:

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

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

You could use Tuples to achieve something similar to @Bryan Watts's Pairing.Of without the extra class:

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

MyFunction(Tuple.Create("foo", 1), Tuple.Create("bar", 2));
鲸落 2024-08-09 05:36:01

所以我是新人,目前无法添加评论,但这只是一个建议,通过使其通用化来改进 @Bryan Watts 对 Pairing.of 类的想法,使其易于被使用其他课程。

public class Pairing 
{
    public static KeyValuePair<TKey, TValue> of<TKey, TValue>(TKey key, TValue value)
    {
        return new KeyValuePair<TKey, TValue>(key, value);
    }
}

So I'm new and can't currently add comments, but this is just a suggestion to improve @Bryan Watts's idea of the Pairing.of class by making it generic, allowing it to be easily used by other classes.

public class Pairing 
{
    public static KeyValuePair<TKey, TValue> of<TKey, TValue>(TKey key, TValue value)
    {
        return new KeyValuePair<TKey, TValue>(key, value);
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文