使用反射调用方法时处理空参数
我正在尝试编写从参数列表推断类型的代码,然后调用与这些参数匹配的方法。这非常有效,除非参数列表中有 null
值。
我想知道如何使 Type.GetMethod
调用匹配函数/重载,即使参数列表中有 null
参数也是如此。
object CallMethodReflection(object o, string nameMethod, params object[] args)
{
try
{
var types = TypesFromObjects(args);
var theMethod = o.GetType().GetMethod(nameMethod, types);
return (theMethod == null) ? null : theMethod.Invoke(o, args);
}
catch (Exception ex)
{
return null;
}
}
Type[] TypesFromObjects(params object[] pParams)
{
var types = new List<Type>();
foreach (var param in pParams)
{
types.Add((param == null) ? null : param.GetType());
}
return types.ToArray();
}
主要问题行是 types.Add((param == null) ? null : param.GetType());
,这将导致 GetMethod
调用失败并显示types 数组中的 null
值。
void Function1(string arg1){ }
void Function1(string arg1, string arg2){ }
void Function1(string arg1, string arg2, string arg3){ }
void Function2(string arg1){ }
void Function2(string arg1, int arg2){ }
void Function2(string arg1, string arg2){ }
/*1*/ CallMethodReflection(obj, "Function1", "String", "String"); // This works
/*2*/ CallMethodReflection(obj, "Function1", "String", null); // This doesn't work, but still only matches one overload
/*3*/ CallMethodReflection(obj, "Function2", "String", "String"); // This works
/*4*/ CallMethodReflection(obj, "Function2", "String", null); // This doesn't work, and I can see why this would cause problems
主要是,我试图确定如何更改我的代码,以便行 /*2*/
也能正常工作。
I'm trying to write code that will infer types from a parameter list and then call the method that matches those parameters. This works very well, except when the parameter list has a null
value in it.
I am wondering how I might cause the Type.GetMethod
call to match a function/overload, even with a null
parameter in the parameters list.
object CallMethodReflection(object o, string nameMethod, params object[] args)
{
try
{
var types = TypesFromObjects(args);
var theMethod = o.GetType().GetMethod(nameMethod, types);
return (theMethod == null) ? null : theMethod.Invoke(o, args);
}
catch (Exception ex)
{
return null;
}
}
Type[] TypesFromObjects(params object[] pParams)
{
var types = new List<Type>();
foreach (var param in pParams)
{
types.Add((param == null) ? null : param.GetType());
}
return types.ToArray();
}
The main problem line is the types.Add((param == null) ? null : param.GetType());
, which will cause the GetMethod
call to fail with a null
value in the types array.
void Function1(string arg1){ }
void Function1(string arg1, string arg2){ }
void Function1(string arg1, string arg2, string arg3){ }
void Function2(string arg1){ }
void Function2(string arg1, int arg2){ }
void Function2(string arg1, string arg2){ }
/*1*/ CallMethodReflection(obj, "Function1", "String", "String"); // This works
/*2*/ CallMethodReflection(obj, "Function1", "String", null); // This doesn't work, but still only matches one overload
/*3*/ CallMethodReflection(obj, "Function2", "String", "String"); // This works
/*4*/ CallMethodReflection(obj, "Function2", "String", null); // This doesn't work, and I can see why this would cause problems
Mainly, I'm trying to determine how to change my code so that line /*2*/
works as well.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
GetMethod 调用有一些重写,它采用从 Binder 类派生的对象。这允许您覆盖默认方法绑定并根据传递的实际参数返回您想要使用的方法。这基本上也是其他两个答案正在做的事情。这里有一些示例代码:
http://msdn.microsoft。 com/en-us/library/system.reflection.binder.aspx
There are overrides to the GetMethod call which take an object derived from the Binder class. This allows you to override the default method binding and return the method you want to use, based on the actual parameters passed. This is essentially what the two other answers are doing as well. There is some sample code here:
http://msdn.microsoft.com/en-us/library/system.reflection.binder.aspx
没有提到的一个选项是使用 Fasterflect,这是一个旨在使反射任务更轻松、更快的库(通过 IL一代)。
要调用给定命名参数字典(或具有应用作参数的属性的对象)的方法,您可以像这样调用最佳匹配:
如果您拥有的只是参数值及其顺序,则可以使用另一个重载:
PS: 您需要从源代码管理获取最新位才能利用 TryCallMethodWithValues 扩展。
免责声明:我是 Fasterflect 项目的贡献者。
An option that has not been mentioned is to use Fasterflect, a library designed to make reflection tasks easier and faster (through IL generation).
To invoke a method given a dictionary of named parameters (or an object with properties that should be used as parameters), you can invoke the best match like this:
If all you have are the parameter values and their ordering, you can use another overload:
PS: You'll need to obtain the latest bits from source control to take advantage of the TryCallMethodWithValues extension.
Disclaimer: I am a contributor to the Fasterflect project.
对于任何为 null 的参数,您可以只匹配任何引用类型。以下非常简单/简单的代码将适用于您的方法,如图所示,但它不能处理歧义异常或使用 ref/out 参数的更复杂情况或能够将派生类型传递给方法或泛型方法之类的事情。
如果您使用 4.0,那么简单地使用动态可能是更好的选择。
For any parameter that is null you could just match to any reference type. The following very simple/naive code will work for your methods as shown, but it doesn't handle things like exceptions on ambiguities or more complex cases using ref/out parameters or being able to pass a derived type to the method or generic methods.
If you are using 4.0 then simply using dynamic might be a better choice.
我认为你必须这样做:
然后基本上做你自己的重载决议。您可以先尝试现有的方法,捕获异常,然后尝试上面的方法。
I think you would have to do:
Then essentially do your own overload resolution. You could try your existing method first, catch the exception and then try the above.
感谢MSDN 链接以及一些<一个href="https://stackoverflow.com/questions/292437/define-if-a-reflected-type-can-be-cast-to-another-reflected-type/1809539#1809539">额外的SO讨论 和 涉及知名 SO 成员的外部论坛讨论,我尝试实施我自己的解决方案,到目前为止该解决方案对我有用。
我创建了一个继承
Binder
类的类,并将我的逻辑用于处理其中可能的null
参数/类型。由于 Binder 类是一个抽象类,因此您必须重写一些其他成员才能实际使用此代码,但我的大多数重写都位于 Type.DefaultBinder 对象前面。
Thanks to the MSDN link as well as some additional SO discussion and an outside forum discussion involving a prominent SO member, I have tried to implement my own solution, which is working for me so far.
I created a class which inherited the
Binder
class and put my logic to handle the potentiallynull
arguments/types in there.Since the
Binder
class is an abstract class, you have to override a few other members to actually use this code, but most of my overrides just front theType.DefaultBinder
object.我没有测试它,我认为其他答案要好得多,但我想知道为什么这不起作用:
I didn't test it and i think the other answers are much better, but i'm wondering why this wouldn't work:
您可以通过实现自己的 GetMethod 来解决该问题,该方法迭代对象中的所有方法并确定哪一个是最佳匹配,我希望这会有所帮助。
我用您提供的示例测试了以下方法并且它有效
You could approach the problem by implementing your own GetMethod that iterates through all the method in the object and determine which one is the best match, I hope this helps.
I tested the following method with the example you provided and it worked