C# 将匿名类型作为方法参数传递
在我的插件架构中,我目前正在将插件名称(字符串)、方法名称(字符串)和参数(对象数组)传递给我的插件服务,以执行指定的方法并返回结果(类型为T) 插件服务的执行方法如下所示:C# 将匿名类型作为方法参数传递,c#,reflection,anonymous-types,C#,Reflection,Anonymous Types,在我的插件架构中,我目前正在将插件名称(字符串)、方法名称(字符串)和参数(对象数组)传递给我的插件服务,以执行指定的方法并返回结果(类型为T) 插件服务的执行方法如下所示: public TResult Execute<TResult>(string pluginName, string operation, params object[] input) { MethodInfo method = null; TResult result = default(TRe
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;
}
public TResult Execute(字符串pluginName、字符串操作、参数对象[]输入){
MethodInfo method=null;
TResult结果=默认值(TResult);
var plugin=_plugins.Enabled().FirstOrDefault(x=>x.GetType().Name.Equals(pluginName,StringComparison.InvariantCultureIgnoreCase));
if(插件!=null){
方法=plugin.GetType().GetMethods().FirstOrDefault(x=>x.Name==操作);
if(方法!=null){
result=(TResult)method.Invoke(插件,输入);
}
}
返回结果;
}
用法示例:
var url = AppHelper.PluginService.Execute<string>(
"ImagePlugin",
"GetImageUrl",
new object[] { image, size });
var url=AppHelper.PluginService.Execute(
“图像插件”,
“GetImageUrl”,
新对象[]{image,size});
我更愿意做的是传入一个匿名类型(因为我认为这样更可读),即
var url=AppHelper.PluginService.Execute(
“图像插件”,
“GetImageUrl”,
新{image=image,targetSize=size});
如何更改Execute方法以将匿名类型属性映射到插件方法参数
我曾考虑在.NET4.0中使用新的动态类型,但我更喜欢在plugin方法上定义参数,而不是接受一个动态对象
谢谢
本
[更新]
浏览ASP.NET MVC源代码后,将匿名类型拉入对象字典(例如RouteValueDictionary)似乎足够简单。
在反射的帮助下,动态创建linq表达式。虽然这是一个很好的实现,但我并不真的想要所有这些额外的复杂性
根据下面的注释,我可以通过内联指定参数来实现可读性(无需对象数组声明):
var url=AppHelper.PluginService.Execute(“ImagePlugin”,“GetImageUrl”,image,size);
我做过一次。您可以做的是通过反射从函数中获得所需的参数。然后,您可以通过将参数数组中的名称与匿名对象的键相匹配来构建参数数组
希望有帮助:-) 首先,检查System.Addin namespace,您可能会在那里得到一些帮助
其次,您可以使用特定的方法名称和参数创建自己的接口,并让插件实现该接口。您可以在不同的项目中定义插件接口,该接口可以在应用程序和插件项目中引用。有一些方法可以实现这一点,尽管我不会建议任何方法 首先,您可以使用反射,这意味着您必须在
PluginService.Execute
方法中编写大量额外的(容易出错的)代码来获得所需的值
其次,如果您知道要传递给方法的匿名类型的参数,则可以使用下面描述的技术。您可以强制转换到方法中具有相同属性的另一个匿名类型。这是Jon Skeet对相同技术的另一种描述
第三,您可以使用来自的类。例如,ASP.NET MVC就使用了这一点。它在引擎盖下使用反射。然而,在ASP.NET MVC中,要么属性名是众所周知的(
controller
和action
),要么它们的名称无关紧要,因为它们是按原样传递给控制器方法的(id
)。我最终遇到了使用匿名类型作为字典的例子。使用此方法,可以将匿名类型作为方法参数(对象)传递并访问其属性
但是,我还要补充一点,在研究了.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);
}
嗨,我写了一篇关于它的帖子:
我希望这会有所帮助。如果要传递匿名类型,请使用动态对象作为参数。插件的execute方法应该期望参数对象的某些属性才能工作。通过使用动态关键字C#编译器将被指示不要对参数执行类型检查,并允许在插件代码中使用强类型语法。属性名称解析将在运行时进行,如果传递的对象没有此类属性,则将引发异常
var o = new { FirstName = "John", LastName = "Doe" };
var result = MyMethod(o);
string MyMethod(dynamic o)
{
return o.FirstName + " " + o.LastName;
}
此示例将匿名对象转换为字典:
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;
}
如果它是Linq中的一个匿名类型,那么您可以通过传递IEnumerable来轻松实现这一点 下面是一个接收方法的示例
public static void MyMethod<IEnumType>(ref IEnumerable<IEnumType> ienum)
{
using (DataTable dt = new DataTable())
{
ienum.First(ie => true).GetType().GetProperties().ToList().ForEach(pr => dt.Columns.Add(pr.Name, typeof(string))); //Parallelization not possible since DataTable columns must be in certain order
ienum.ToList().ForEach(ie => //Parallelization not possible since DataTable rows not synchronized.
{
List<object> objAdd = new List<object>();
ie.GetType().GetProperties().ToList().ForEach(pr => objAdd.Add(ie.GetType().InvokeMember(pr.Name, BindingFlags.GetProperty, null, ie, null))); //Parallelization not possible since DataTable columns must be in certain order
dt.Rows.Add(objAdd.ToArray());
objAdd.Clear();
objAdd = null;
});
//Do something fun with dt
}
}
公共静态void MyMethod(ref IEnumerable ienum)
{
使用(DataTable dt=newdatatable())
{
ienum.First(ie=>true).GetType().GetProperties().ToList().ForEach(pr=>dt.Columns.Add(pr.Name,typeof(string));//由于数据表列必须按特定顺序排列,因此无法并行化
ienum.ToList().ForEach(ie=>//由于数据表行未同步,无法并行化。
{
List objAdd=新列表();
ie.GetType().GetProperties().ToList().ForEach(pr=>objAdd.Add(即GetType().InvokeMember(pr.Name,BindingFlags.GetProperty,null,ie,null));//由于数据表列必须按特定顺序排列,因此无法并行化
Add(objAdd.ToArray());
objAdd.Clear();
objAdd=null;
});
//用dt做些有趣的事
}
}
当然,由于您使用的是反射,因此您可能会在较慢的机器上看到性能问题,或者在T中有大量IEnumerable或大量属性。使用c#7.0时,您可以使用元组。
public static void ExAnonymousType()
{
var nguoi = new { Ten = "Vinh", Tuoi = 20 };
Console.WriteLine(nguoi.Ten + " " + nguoi.Tuoi);
DoSomeThing(nguoi);
}
private static void DoSomeThing(object nguoi)
{
Console.WriteLine(nguoi.GetType().GetProperty("Ten").GetValue(nguoi,null));
}
AnonymousObjectToDictionary(new { foo = 11, bar = "Be happy" });
public static void MyMethod<IEnumType>(ref IEnumerable<IEnumType> ienum)
{
using (DataTable dt = new DataTable())
{
ienum.First(ie => true).GetType().GetProperties().ToList().ForEach(pr => dt.Columns.Add(pr.Name, typeof(string))); //Parallelization not possible since DataTable columns must be in certain order
ienum.ToList().ForEach(ie => //Parallelization not possible since DataTable rows not synchronized.
{
List<object> objAdd = new List<object>();
ie.GetType().GetProperties().ToList().ForEach(pr => objAdd.Add(ie.GetType().InvokeMember(pr.Name, BindingFlags.GetProperty, null, ie, null))); //Parallelization not possible since DataTable columns must be in certain order
dt.Rows.Add(objAdd.ToArray());
objAdd.Clear();
objAdd = null;
});
//Do something fun with dt
}
}
public static void ExAnonymousType()
{
var nguoi = new { Ten = "Vinh", Tuoi = 20 };
Console.WriteLine(nguoi.Ten + " " + nguoi.Tuoi);
DoSomeThing(nguoi);
}
private static void DoSomeThing(object nguoi)
{
Console.WriteLine(nguoi.GetType().GetProperty("Ten").GetValue(nguoi,null));
}