【问题标题】:Concise Method for Passing Associative Arrays to Method将关联数组传递给方法的简洁方法
【发布时间】:2010-10-06 13:23:16
【问题描述】:

寻找一种将关联数组传递给方法的方法。我正在寻找用 C# 重写一个 Actionscript 补间包,但遇到了“关联”数组/对象的问题。通常在 Actionscript 中,我可能会执行以下操作:

public function tween(obj:DisplayObject, params:Object = null):void {
    if (params.ease != null) {
        //do something
    }
    //...
}

这可以这样称呼:

tween(this, {ease:'out', duration:15});

我正在寻找一种在 C# 中执行相同操作的方法。到目前为止,我已经收集了以下选项:

a) 创建一个类或结构来定义可能的参数键和类型并传递它

b) 将参数作为泛型类型传递

tween(frameworkElement, new {ease = 'out', duration = 15});

假设

public static void tween(FrameworkElement target, object parameters);

并找出一些在补间函数中使用它的方法(我不确定如何分离给定对象的 key=value。有什么想法吗?)

c) 创建Dictionary<string, object> 将参数传递给补间函数

还有其他想法或示例代码吗?我是 C# 的新手。

编辑

花了我一整天才弄明白:

“匿名类型不能跨程序集边界共享。编译器确保每个程序集中给定的属性名称/类型对序列最多有一个匿名类型。要在程序集之间传递结构,您需要正确定义它们。”

【问题讨论】:

    标签: c# silverlight associative-array parameter-passing


    【解决方案1】:

    编辑:这基本上是 HtmlHelper 扩展在 ASP.NET MVC 中使用的机制。这不是我原创的。


    我更喜欢具有两个不同签名的混合方法。注意:我没有尝试过,这两个签名之间可能存在冲突,因此您可能必须给第二种方法一个稍微不同的名称,以允许编译器在它们之间进行选择,但我不这么认为。

    public static void tween( FrameworkElement target, object parameters )
    {
        return tween( target, new ParameterDictionary( parameters ) );
    }
    
    public static void tween( FrameworkElement target,
                              ParameterDictionary values )
    {
        if (values.ContainsKey( "ease" ))
        {
          ....
        }
    }
    

    然后你有一个 ParameterDictionary 类,它使用匿名类型的反射并设置字典。

    public class ParameterDictionary : Dictionary<string,object>
    {
        public ParameterDictionary( object parameters )
        {
             if (parameters != null)
             {
                 foreach (PropertyInfo info in parameters.GetType()
                                                         .GetProperties())
                 {
                     object value = info.GetValue(parameters,null);
                     this.Add(info.Name,value);
                 }
             }
        }
    }
    

    这为您提供了易用性和易用性——“丑陋”的反射内容被包裹在字典的单个构造函数中,而不是在您的方法中。而且,当然,字典可以反复用于类似的目的,而反射代码只需编写一次。

    【讨论】:

    • 这太棒了。我想我可以用这个运行。
    • 我试过了,但在 info.GetValue() 调用中出现 System.MethodAccessException 错误。
    • 除了从 Dictionary 派生之外,我只是在 SnippetCompiler 中尝试过,没有任何问题。我正在调用代码: var dict = new ParameterDictionary(new { ID = 1, Value = "test" } );
    • 您使用的是什么版本的框架?我在 SnippetCompiler 中使用 .NET 3.5 sp1 尝试了您的示例,没有任何问题。
    • 您是否尝试过使用不带 BindingFlags 的 GetProperties() 方法?它们不应该是必需的,因为默认是获取公共实例属性。另请注意,我添加了对 null 参数的检查。
    【解决方案2】:

    字典是一种合理的方法。它可能看起来像这样:

    public static void tween(FrameworkElement target, IDictionary<string, object> parameters)
    {
        if (parameters.ContainsKey("ease")) {
            //do something
        }
    }
    

    请注意,当您传入值时,可以使用缩短的集合初始化语法使其更容易,例如:

    tween(something, new Dictionary<string, object> { { "ease", "out" }, { duration, 15 } });
    

    这将是一种与 ActionScript 代码大致“相同”的快速方法,但它并不是真正出色的 C#。 C#-ish 的方法是创建一个真正的 TweenParameters 结构或类,为每个可能的参数提供属性,然后创建一个传递给 tween()。这通常被认为更易于维护,因为所有“可用”属性对调用者来说都是显而易见的,而无需查看 tween() 的内部结构,并且因为它在编译时捕获了字符串比较直到运行时才会注意到的错误,例如拼写“持续时间”“duratoin”。

    【讨论】:

    • 我确实喜欢在结构中维护一个“正确”可用参数列表的想法。
    【解决方案3】:

    我自己是选项 (b) 的粉丝 - 传递一个匿名类型并使用反射解析出值。

    我看到其他人使用 lambda 表达式实现了同样的目标。调用语法是:

    tween(frameworkElement, ease => "out", duration => 15);
    

    声明大致如下:

    public static void tween(FrameworkElement target, params Expression<Func<object>>[] parameters) { ... }
    

    这个想法是您可以采用可变数量的“返回对象的函数”。然后,您从每个Expression<TDelegate> 中解析出参数的名称,并调用每个参数以获取其值。

    我认为这并不比反映匿名类型更好,但这是另一种需要考虑的方法。

    更新

    我实际上已经在我的博客here 和here 上写过关于将关联数组作为字典传递的想法。

    【讨论】:

    • 这是一个有趣的想法。这似乎有点滥用(将您定义的“函数”视为除了传递您的硬编码数据之外实际上并没有做任何事情)但它很整洁。
    • 是的,我自己更喜欢匿名类型。
    猜你喜欢
    • 1970-01-01
    • 2021-07-25
    • 2021-08-21
    • 1970-01-01
    • 1970-01-01
    • 2015-12-20
    • 2019-03-03
    • 1970-01-01
    • 2010-10-23
    相关资源
    最近更新 更多