65.9K
CodeProject 正在变化。 阅读更多。
Home

通过反射调用 Lambda 函数

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.82/5 (11投票s)

2010 年 8 月 10 日

CPOL

2分钟阅读

viewsIcon

39810

downloadIcon

267

如何通过反射调用强类型 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 日:首次修订
© . All rights reserved.