传递匿名类型作为方法参数

Ben*_*ter 22 c# reflection anonymous-types

在我的插件架构中,我目前正在将插件名称(字符串),方法名称(字符串)和参数(对象数组)传递给我的插件服务,以执行指定的方法并返回结果(类型为T).

插件服务的execute方法如下所示:

public TResult Execute<TResult>(string pluginName, string operation, params object[] input) {
    MethodInfo method = null;
    TResult result = default(TResult);

    var plugin = _plugins.Enabled().FirstOrDefault(x => x.GetType().Name.Equals(pluginName,  StringComparison.InvariantCultureIgnoreCase));

    if (plugin != null) {
        method = plugin.GetType().GetMethods().FirstOrDefault(x => x.Name == operation);
        if (method != null) {
            result = (TResult)method.Invoke(plugin, input);
        }
    }
    return result;
  }
Run Code Online (Sandbox Code Playgroud)

示例用法:

var url = AppHelper.PluginService.Execute<string>(
    "ImagePlugin",
    "GetImageUrl",
    new object[] { image, size });
Run Code Online (Sandbox Code Playgroud)

我宁愿做的是传递匿名类型(因为我认为这更具可读性)即

var url = AppHelper.PluginService.Execute<string>(
    "ImagePlugin",
    "GetImageUrl",
    new { image = image, targetSize = size });
Run Code Online (Sandbox Code Playgroud)

如何更改我的Execute方法以将匿名类型属性映射到我的插件方法参数?

我曾考虑在.net 4.0中使用新的动态类型,但我更喜欢在插件方法上定义我的参数而不是接受一个动态对象.

谢谢Ben

[更新]

在查看ASP.NET MVC源代码之后,将匿名类型拉入对象字典(例如RouteValueDictionary)似乎很简单.在反射的帮助下,动态创建linq表达式.虽然它是一个很好的实现,但我并不是真的想要所有这些额外的复杂性.

根据下面的注释,我只需通过内联指定参数(不需要对象数组声明)就可以实现可读性:

var url = AppHelper.PluginService.Execute<string>("ImagePlugin", "GetImageUrl", image, size);
Run Code Online (Sandbox Code Playgroud)

Ben*_*ter 21

我最终遇到了这篇文章,演示了如何使用匿名类型作为词典.使用此方法,您可以将匿名类型作为方法参数(对象)传递并访问其属性.

但是,我还要补充一点,在查看.net 4.0中的新动态功能(例如ExpandoObject)之后,将动态对象作为参数传递会感觉更清晰:

        dynamic myobj = new ExpandoObject();
        myobj.FirstName = "John";
        myobj.LastName = "Smith";

        SayHello(myobj);
        ...........

        public static void SayHello(dynamic properties)
        {
           Console.WriteLine(properties.FirstName + " " + properties.LastName);
        }
Run Code Online (Sandbox Code Playgroud)


小智 12

如果要传递匿名类型,请使用动态对象作为参数.插件的execute方法应该期望参数对象的某些属性才能工作.通过使用动态关键字,将指示C#编译器不对参数执行类型检查,并允许在插件代码中使用强类型语法.属性名称解析将在运行时发生,如果传递的对象没有此类属性,则将抛出异常.

var o = new { FirstName = "John", LastName = "Doe" };

var result = MyMethod(o);

string MyMethod(dynamic o)
{
    return o.FirstName + " " + o.LastName;
}
Run Code Online (Sandbox Code Playgroud)

阅读此博客文章中的更多内容


Ron*_*erg 9

有一些方法可以实现这一点,虽然我不会建议任何一个.

首先,您可以使用反射,这意味着您必须在方法中编写许多其他(容易出错的)代码PluginService.Execute以获取所需的值.

其次,如果您知道要传递给方法的匿名类型的参数,则可以使用此处描述的技术.您可以在方法内部转换为具有相同属性的另一个匿名类型.是Jon Skeet对同一技术的另一种描述.

第三,你可以使用来自的类System.ComponentModel.例如,ASP.NET MVC使用它.它使用引擎盖下的反射.然而,在ASP.NET MVC无论是属性名称是众所周知的(controlleraction例如)或它们的名称并不重要,因为它们原样传递到控制器方法(id例如).


Pav*_*uva 7

此示例将匿名对象转换为字典:

IDictionary<string, object> AnonymousObjectToDictionary(object propertyBag)
{
    var result = new Dictionary<string, object>();
    if (propertyBag != null)
    {
        foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(propertyBag))
        {
            result.Add(property.Name, property.GetValue(propertyBag));
        }
    }
    return result;
}
Run Code Online (Sandbox Code Playgroud)

你可以这样称呼它:

AnonymousObjectToDictionary(new { foo = 11, bar = "Be happy" });
Run Code Online (Sandbox Code Playgroud)