[英]How do I invoke an extension method using reflection?
我很感激之前有人问过类似的问题,但我很难在以下代码中调用 Linq Where方法。 我希望使用反射来动态调用此方法,并动态构建Where子句中使用的委托(或 lambda)。 这是一个简短的代码示例,一旦工作,将有助于形成我正在构建的解释型 DSL 的一部分。 干杯。
public static void CallWhereMethod()
{
List<MyObject> myObjects = new List<MyObject>(){new MyObject{Name="Jon Simpson"}};
System.Delegate NameEquals = BuildEqFuncFor<MyObject>("Name", "Jon Simpson");
object[] atts = new object[1] ;
atts[0] = NameEquals;
var ret = typeof(List<MyObject>).InvokeMember("Where", BindingFlags.InvokeMethod, null, InstanceList,atts);
}
public static Func<T, bool> BuildEqFuncFor<T>(string prop, object val)
{
return t => t.GetType().InvokeMember(prop,BindingFlags.GetProperty,
null,t,null) == val;
}
正如其他人所说,扩展方法是编译器魔术,您可以随时使用VS右键单击,转到定义找到实现静态方法的真实类型。
从那里,它变得相当多毛。 Where
是重载的,因此您需要找到与您想要的签名匹配的实际定义。 GetMethod
对泛型类型有一些限制,因此您必须使用搜索找到实际的类型。
找到该方法后,您必须使用MakeGenericMethod
调用使MethodInfo
特定。
这是一个完整的工作示例:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
namespace ConsoleApplication9 {
class Program {
class MyObject {
public string Name { get; set; }
}
public static void CallWhereMethod() {
List<MyObject> myObjects = new List<MyObject>() {
new MyObject { Name = "Jon Simpson" },
new MyObject { Name = "Jeff Atwood" }
};
Func<MyObject, bool> NameEquals = BuildEqFuncFor<MyObject>("Name", "Jon Simpson");
// The Where method lives on the Enumerable type in System.Linq
var whereMethods = typeof(System.Linq.Enumerable)
.GetMethods(BindingFlags.Static | BindingFlags.Public)
.Where(mi => mi.Name == "Where");
Console.WriteLine(whereMethods.Count());
// 2 (There are 2 methods that are called Where)
MethodInfo whereMethod = null;
foreach (var methodInfo in whereMethods) {
var paramType = methodInfo.GetParameters()[1].ParameterType;
if (paramType.GetGenericArguments().Count() == 2) {
// we are looking for Func<TSource, bool>, the other has 3
whereMethod = methodInfo;
}
}
// we need to specialize it
whereMethod = whereMethod.MakeGenericMethod(typeof(MyObject));
var ret = whereMethod.Invoke(myObjects, new object[] { myObjects, NameEquals }) as IEnumerable<MyObject>;
foreach (var item in ret) {
Console.WriteLine(item.Name);
}
// outputs "Jon Simpson"
}
public static Func<T, bool> BuildEqFuncFor<T>(string prop, object val) {
return t => t.GetType().InvokeMember(prop, BindingFlags.GetProperty,
null, t, null) == val;
}
static void Main(string[] args) {
CallWhereMethod();
Console.ReadKey();
}
}
}
扩展方法实际上只是水下的静态方法。 像 foo.Frob( arguments ) 这样的扩展方法调用实际上只是 SomeClass.Frob(foo, arguments )。 在 Where 方法的情况下,您正在寻找 System.Linq.Enumerable.Where。 因此,获取 Enumerable 的 typeof 并调用 Where 。
我有点晚了,但是如果您需要调用 IEnumerable 类型未知的 Linq 扩展,这可以帮助您。
IEnumerable<dynamic> test = obj as IEnumerable<dynamic>;
然后也许测试 obj 如果不是 null 和
int count = test.Count()
对我来说效果很好。
您的代码示例有点令人困惑……除非 MyObject 是可枚举的。
使用反射,您必须调用 System.Linq.Enumerable 上的 Where,传入您想要执行 Where on 的枚举。
这是方法名称唯一的一般情况的答案(因此与原始发布的情况不同,因为 Enumerable.Where 已重载)。
假设您有一个扩展类型的目标对象targetObject
,其中扩展方法在类TargetClassExtensions
定义,其扩展方法的名称是ExtensionMethod
,它接受一个整数参数并且是您想要为类TargetGenericClass
调用的TargetGenericClass
.
然后,要通过反射调用此扩展方法,请执行以下操作:
int inputInteger = 9; // Example input for the generic method.
object? result = typeof(TargetClassExtensions)
.GetMethod(nameof(TargetClassExtensions.ExtensionMethod))
.MakeGenericMethod(typeof(TargetGenericClass))
.Invoke(null, new object[] { targetObject, inputInteger });
扩展方法是 ac# 编译器技巧,它们不存在于相关类型中。 它们(这些特定的)存在于 System.Linq 名称空间内的静态类中。 我建议在反射器中反映这一点,然后对这些类型进行反射。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.