This is best explained using code. I have a generic class that has a method that returns an integer. Here is a simple version for the purposes of explaining…
public class Gen<T>
{
public int DoSomething(T instance)
{
// Real code does something more interesting!
return 1;
}
}
At runtime I use reflection to discover the type of something and then want to create an instance of my Gen class for that specific type. That is easy enough and done like this…
Type fieldType = // This is the type I have discovered
Type genericType = typeof(Gen<>).MakeGenericType(fieldType);
object genericInstance = Activator.CreateInstance(genericType);
I now want to create an Expression that will take as a parameter an instance of the generic type and then calls the DoSomething method of that type. So I want the Expression to effectively perform this…
int answer = genericInstance.DoSomething(instance);
…except I do not have the ‘instance’ until some point later at runtime and the genericInstance is the generated type as can be seen above. My attempt at creating the Lambda for this is as follows…
MethodInfo mi = genericType.GetMethod("DoSomething",
BindingFlags.Instance | BindingFlags.Public);
var p1 = Expression.Parameter(genericType, "generic");
var p2 = Expression.Parameter(fieldType, "instance");
var x = Expression.Lambda<Func<genericType, fieldType, int>>
(Expression.Call(p1, mi, p2),
new[] { p1, p2 }).Compile();
…so that later on I can call it with something like this…
int answer = x(genericInstance, instance);
Of course, you cannot provide Func with instance parameters and so I have no idea how to parameterize the Lambda generation. Any ideas?
I think you would just use the
Expression.Lambdathat takes the delegate type as a type rather then as a generic, and create your Func on the fly like you are withGen<>:This will return a Delegate rather than a strongly typed
Func, but you can of course cast it if needed (and seemingly difficult if you don’t know what you are casting to), or dynamically invoke it usingDynamicInvokeon it.EDIT:
This seems to work without the need of a dynamic invoke.
EDIT 2:
A greatly simplified version: