Esto se explica mejor usando el código. Tengo una clase genérica que tiene un método que devuelve un número entero. Aquí es una versión sencilla para los fines de explicar ...Cómo crear un Expression.Lambda cuando un tipo no se conoce hasta el tiempo de ejecución?
public class Gen<T>
{
public int DoSomething(T instance)
{
// Real code does something more interesting!
return 1;
}
}
En tiempo de ejecución que utiliza la reflexión para descubrir el tipo de algo y luego quieren crear una instancia de mi clase Gen para ese tipo específico. Esto es bastante fácil y hecho así ...
Type fieldType = // This is the type I have discovered
Type genericType = typeof(Gen<>).MakeGenericType(fieldType);
object genericInstance = Activator.CreateInstance(genericType);
ahora quiero crear una expresión que va a tomar como parámetro una instancia del tipo genérico y luego llama al método HacerAlgo de ese tipo. Así que quiero la expresión a cabo de forma efectiva este ...
int answer = genericInstance.DoSomething(instance);
... excepto que no tengo el 'ejemplo' hasta algún momento posterior en tiempo de ejecución y el genericInstance es el tipo generado como se puede ver arriba. Mi intento de crear la Lambda de esto es la siguiente ...
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();
... para que después se puede llamar así con algo como esto ...
int answer = x(genericInstance, instance);
Por supuesto, no puedo proporcionar a Func los parámetros de la instancia y, por lo tanto, no tengo idea de cómo parametrizar la generación de Lambda. ¿Algunas ideas?
Una buena idea que sí funciona. Desafortunadamente, la razón por la que deseo usar un Lambda compilado fuertemente tipado es el rendimiento. Usar DynamicInvoke es bastante lento en comparación con un Lambda tipado. –
¿Es posible capturar variables en un árbol de Expresión? Ayudaría a capturar la instancia genérica ya que eso nunca cambiará. –
@PhilWright Hm, ya veo. Déjame ver qué más puedo inventar. – vcsjones