有没有比使用字典作为参数

时间:2017-12-09 21:20:26

标签: c#

是否有更有效的方法。

功能:

public void someFunction(Dictionary<string, object> args){
   foreach (var item in args){
       Console.WriteLine("key: " + item.Key + " value: " + item.Value);
   }
}

调用功能并不好看:&lt; - 这是问题

someFunction(new Dictionary<string, object>
        {
            { "number", 3 },
            { "text", "Some Text" }
}));

输出:

key: number value: 3
key: text value: Some Text

我希望实现类似的地方,我总能更改传递的变量名称和值

someFunction(["number" => 3, "text" => "Some Text"]);

我想将一个字符串名称和一个对象类型数组传递给该函数,以便我可以遍历它。这段代码有效,但我希望它看起来更整洁。

在PHP中有http://php.net/manual/en/function.compact.php

这使得它能够在代码中使用变量的名称和数组中的值。使用c#我必须使用整个字典。

我希望看到一种更有效的方式。

编辑: 谢谢你们。我不知道我会得到这么快的答案0_0

5 个答案:

答案 0 :(得分:3)

当然,您可以使用params关键字来允许动态数量的参数

您可以举例说明(它不一定是KeyValuePair<string, object>,也可以是Tuple<string, object>

public void AddSomeKeys(params KeyValuePair<string, object>[] arguments) {
    foreach (var item in arguments){
        Console.WriteLine($"key: {item.Key} value: {item.Value}");
    }
}

在C#7中,通过使用ValueTuple

,您可以更轻松一点
public void AddSomeKeys(params (string key, object value)[] arguments) {
    foreach (var item in arguments){
        Console.WriteLine($"key: {item.key} value: {item.value}");
    }
}

或者你可以使用更匿名的ValueTuple

public void AddSomeKeys(params (string, object)[] arguments) {
    foreach (var item in arguments){
        Console.WriteLine($"key: {item.Item1} value: {item.Item2}");
    }
}

在这两种情况下,您都可以调用以下方法:

AddSomeKeys(new KeyValuePair<string, object>( "item1", "value1" ), new KeyValuePair<string, object>( "item2", "value2" ) );

或使用第二个版本

AddSomeKeys( ( key: "item1", value: "value1" ), ( key: "item2", value: "value2" ) );

或使用第三个版本

AddSomeKeys( ( "item1", "value1" ), ( "item2", "value2" ) );

答案 1 :(得分:3)

如果您只是为调用者寻找稀疏语法,则可以使用匿名类型,类似于jquery传递可选选项的方式。例如:

public static void someFunction(object input)
{
    foreach (var p in input.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public))
             Console.WriteLine("{0}={1}", p.Name, p.GetValue(input));
}

函数本身有点乱,但对于调用者来说,语法非常轻量级:

someFunction( new { Number = 3, Text = "Some text"});

输出:

Number=3
Text=Some text

如果你计划这么做,你可以用扩展方法减少痛苦。我将我的名字Extract()命名为:

using System;
using System.Linq;
using System.Collections.Generic;
using System.Reflection;

public static class ExtensionMethods
{
    public static Dictionary<string, object> Extract<T>(this T input) where T : class
    {
        return input
            .GetType()
            .GetProperties(BindingFlags.Public | BindingFlags.Instance)
            .ToDictionary( p => p.Name, p => p.GetValue(input));
    }
}

public class Program
{
    public static void someFunction(object input)
    {
        var parameters = input.Extract();  //Magic

        Console.WriteLine("There were {0} parameters, as follows:", parameters.Count);
        foreach (var p in parameters)
        {
            Console.WriteLine("{0}={1}", p.Key, p.Value);
        }
    }

    public static void Main()
    {
        someFunction(new { number = 3, text = "SomeText" } );
        someFunction(new { another = 3.14F, example = new DateTime(2017, 12, 15) } );
    }
}

DotNetFiddle上的输出:

There were 2 parameters, as follows:
number=3
text=SomeText
There were 2 parameters, as follows:
another=3.14
example=12/15/2017 12:00:00 AM

这种方法的主要缺点是你不能使用接口或做任何事情来要求存在某些键。此外,你必须使用反射,这是一个更多的工作。如果您想避免这些缺点,可以使用相同的方法但使用非匿名类型,如下所示:

class SomeFunctionParams
{
    public int Number { get; set; }
    public string Text { get; set; }
}

public static void someFunction(SomeFunctionParams params)
{
    Console.WriteLine("Number={0}", params.Number);
    Console.WriteLine("Text={0}", params.Text);
}

...但是你会失去匿名类型的动态优势。

另一个选项是将每个可能的键作为可选参数公开,并且只提供您想要的键:

void someFunction(int Number = default(int), string Text = default(string), DateTime SomeOtherParam = default(DateTime))
{
    if (Number != default(int)) Console.WriteLine("Number={0}", Number);
    if (Text != default(string)) Console.WriteLine("Text={0}", Text);
    if (SomeOtherParam != default(DateTime)) Console.WriteLine("SomeOtherParam={0}", SomeOtherParam);
}

someFunction(Number : 3, Text : "Some text");

答案 2 :(得分:1)

C# 6 added a new syntax使内联初始化更容易阅读:

someFunction(new Dictionary<string, object> {
    ["number"]=3, ["text"]="Some Text"
});

答案 3 :(得分:0)

怎么样:

public static void Main()
{
    Iterate(new Dictionary<string, object> { ["1"] = "one", ["2"] = "Two" });
    Console.Read();
}

public static void Iterate(Dictionary<string, object> args)
{
    foreach (var item in args)
    {
        Console.WriteLine("key: " + item.Key + " value: " + item.Value);
    }
}

答案 4 :(得分:0)

您可以在文件的开头使用alias

using D = System.Collections.Generic.Dictionary<string, object>;

using System.Collections.Generic;

Namespace {
    using D = Dictionary<string, object>;

然后使用D代替Dictionary<string, object>

public void someMethod(D args){
   foreach (var item in args){
       Console.WriteLine("key: " + item.Key + " value: " + item.Value);
   }
}

someMethod(new D { { "number", 3 }, { "text", "Some Text" } }));

如果所有参数都已知,那么使用optional arguments会更有效:

void someMethod(int a = 0, int b = 0, int c = 0, int d = 0, int e = 0){
    Console.WriteLine($"key: {nameof(a)} value: {a}");
    Console.WriteLine($"key: {nameof(b)} value: {b}");
    // ...
}

和样品使用:

someMethod(d: 1, b: 2);