Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Invoke a Lambda Function through Reflection

0.00/5 (No votes)
10 Aug 2010 1  
How to call a strongly-typed lambda function with reflection

Introduction

At work, I was writing a small library for a customer - in this library, you are able to setup strongly-typed seaching objects that use lambda expressions to search through a domain model.

All-in-all, a nice little library that worked fast and was easy to use. But I came across a problem when I needed to combine two or more search-objects. It is a small article that shows you how you can invoke a generic lambda function through reflection.

Background

If you have the following class defined in your domainmodel:

public class LambdaClass<T>
{
    public Func<T, bool> TestMethod { get; set; }

    public LambdaClass(Func<T, bool> testMethod)
    {
        TestMethod = testMethod;
    }
} 

You can use this class like this:

LambdaClass<string> lambdaTest = 
                    new LambdaClass<string>(entry => entry.Contains("Tom"));

if (lambdaTest.TestMethod("My name is Tom")) {
    Console.WriteLine("Yes it is"); 
}

This is all fine - but what if I need to call the TestMethod on the LambdaClass but I don't know the generic type?!

Using the Code

It is possible and to do this, but we have to introduce a new interface for all of this to work properly - we need to make a little abstraction and have the possibility to get the generic type.

If we introduce this interface:

public interface ILambdaClass
{
    Type GetImplementedType { get; }
}

And then get our LambdaClass to implement this interface like this:

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);
        }
    } 
}

It is now possible for use to get the generic type of the LambdaClass instance, and with this in hand, we can use reflection to create the strongly-typed type via reflection and then call the lambda expression:

// 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");
}

The Dynamic Way

All of this is a lot of code and there is actually a better way of doing this - at least what this code is doing. If you know the name of the method you want to call and the exact number of parameters, you can use dynamic instead.

This small piece of code does exactly the same:

dynamic lambdaDyn = lambdaTest;
if (lambdaDyn.TestMethod("My name is Tom"))
{
    Console.WriteLine("Yes it is");
} 

A lot lesser code, cleaner and just as safe - if you can do it in .NET 4.0.

Comment

Calling generic lambda Func<,> expression through reflection can be quite difficult, but when you dig down into it is not that difficult. And if you can - try to use dynamic instead - that is my lesson.

History

  • 10th August, 2010: First revision

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here