通过反射调用 Lambda 函数






4.82/5 (11投票s)
如何通过反射调用强类型 lambda 函数。
引言
在工作中,我为一位客户编写了一个小型库 - 在这个库中,你可以设置使用 lambda 表达式来搜索领域模型的强类型搜索对象。
总而言之,这是一个不错的库,运行速度快且易于使用。但是,当我需要组合两个或多个搜索对象时,我遇到了一个问题。这是一篇小文章,展示了如何通过反射调用泛型 lambda 函数。
背景
如果在你的领域模型中定义了以下类
public class LambdaClass<T>
{
public Func<T, bool> TestMethod { get; set; }
public LambdaClass(Func<T, bool> testMethod)
{
TestMethod = testMethod;
}
}
你可以像这样使用这个类
LambdaClass<string> lambdaTest =
new LambdaClass<string>(entry => entry.Contains("Tom"));
if (lambdaTest.TestMethod("My name is Tom")) {
Console.WriteLine("Yes it is");
}
这些都很好 - 但是,如果我需要调用 LambdaClass
上的 TestMethod
,但我不知道泛型类型怎么办?
Using the Code
这是可能的,但为了使所有这些正常工作,我们必须引入一个新的接口 - 我们需要进行一些抽象,并获得泛型类型的可能性。
如果我们引入这个接口
public interface ILambdaClass
{
Type GetImplementedType { get; }
}
然后让我们的 LambdaClass
实现这个接口,就像这样
public class LambdaClass<T> : ILambdaClass
{
public Func<T, bool> TestMethod { get; set; }
public LambdaClass(Func<T, bool> testMethod)
{
TestMethod = testMethod;
}
public Type GetImplementedType
{
get
{
return typeof(T);
}
}
}
现在我们可以获取 LambdaClass
实例的泛型类型,并利用这一点,通过反射创建强类型,然后调用 lambda 表达式
// Get the generic type of the lambdaClass
Type lambdaClassType = typeof(LambdaClass<>)
.MakeGenericType(
((ILambdaClass)lambdaTest).GetImplementedType
);
// Create the lambdafunction type by using the generic type
Type lambdaFunc = typeof(Func<,>)
.MakeGenericType(
((ILambdaClass)lambdaTest)
.GetImplementedType,
typeof(bool)
);
// Get the actual lambda expression from the object instance
var testMethodProperty = lambdaClassType
.InvokeMember(
"TestMethod",
System.Reflection.BindingFlags.GetProperty,
null,
lambdaTest,
null);
// Now we call Invoke on the actual lambda expression to invoke the method
// given the correct type and parameters
bool success = (bool)lambdaFunc
.InvokeMember(
"Invoke",
System.Reflection.BindingFlags.InvokeMethod,
null,
testMethodProperty,
new object[] { "My name is Tom" }
);
if (success)
{
Console.WriteLine("Yes it is");
}
动态方式
所有这些代码都很多,实际上还有一种更好的方法来做这件事 - 至少对于这段代码来说是这样。如果你知道要调用的方法名称和确切的参数数量,你可以使用 dynamic
代替。
这段小代码执行完全相同的操作
dynamic lambdaDyn = lambdaTest;
if (lambdaDyn.TestMethod("My name is Tom"))
{
Console.WriteLine("Yes it is");
}
代码更少,更简洁,而且同样安全 - 如果你可以在 .NET 4.0 中做到这一点。
注释
通过反射调用泛型 lambda Func<,>
表达式可能很困难,但当你深入研究时,它并不难。如果可以的话 - 尝试使用 dynamic 代替 - 这是我的经验教训。
历史
- 2010 年 8 月 10 日:首次修订