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:
Type lambdaClassType = typeof(LambdaClass<>)
.MakeGenericType(
((ILambdaClass)lambdaTest).GetImplementedType
);
Type lambdaFunc = typeof(Func<,>)
.MakeGenericType(
((ILambdaClass)lambdaTest)
.GetImplementedType,
typeof(bool)
);
var testMethodProperty = lambdaClassType
.InvokeMember(
"TestMethod",
System.Reflection.BindingFlags.GetProperty,
null,
lambdaTest,
null);
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