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)
有一些方法可以实现这一点,虽然我不会建议任何一个.
首先,您可以使用反射,这意味着您必须在方法中编写许多其他(容易出错的)代码PluginService.Execute以获取所需的值.
其次,如果您知道要传递给方法的匿名类型的参数,则可以使用此处描述的技术.您可以在方法内部转换为具有相同属性的另一个匿名类型.这是Jon Skeet对同一技术的另一种描述.
第三,你可以使用来自的类System.ComponentModel.例如,ASP.NET MVC使用它.它使用引擎盖下的反射.然而,在ASP.NET MVC无论是属性名称是众所周知的(controller和action例如)或它们的名称并不重要,因为它们原样传递到控制器方法(id例如).
此示例将匿名对象转换为字典:
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)