Convertir Func expresión a Func donde T es una restricción genérica

c# expression-trees generics typeconverter

Pregunta

Tengo esta función estática

public static object Create(Type t)
{
    //unimportant
}

No tengo control sobre la función anterior de arriba, así que no puedo alterarla. El problema es que no es genérico, por lo que tengo que convertir el objeto devuelto a algún tipo. Este tipo es proporcionado por la restricción de otra clase genérica desde donde llamo al método Create .

Aquí es donde he llegado:

public static class Creator<T>
{
    public static void Create()
    {
        var m = typeof(SomeClass).GetMethod("Create");
        var p = Expression.Parameter(typeof(Type));
        var e = Expression.Call(m, p);

        //at this stage I want to create delegate for calling the 'Create' method, 
        //then pass typeof(T) as parameter, get returned object, 
        //and finally cast it to 'T'.

        //for eg, I can do it like this:
        var f = Expression.Lambda<Func<Type, object>>(e, p).Compile();
        Func<T> mainThing = () => (T)f(typeof(T));

        //is there a way I can achieve in one step?
    }
}

En mi enfoque anterior, no estoy compilando el delegado final sino un paso anterior. ¿Cómo incorporo el modelo también antes de la compilación y Func<T> ?

Respuesta aceptada

Creo que solo necesitas una llamada a Expression.Convert , y usar una ConstantExpression lugar de una ParameterExpression :

var method = typeof(SomeClass).GetMethod("Create");
var call = Expression.Call(method, Expression.Constant(typeof(T), typeof(Type)));
var conversion = Expression.Convert(call, typeof(T));
var function = Expression.Lambda<Func<T>>(conversion).Compile();

(No lo he probado, pero se ve bien ...)


Respuesta popular

Pareces estar saltando a través de muchos aros innecesarios. No entiendo por qué haces esto a través de un árbol de expresiones. ¿Por qué no solo?

public static class Creator<T>
{
    public static void Create()
    {
        Func<T> mainThing = () => (T)SomeClass.Create(typeof(T));
    }
}

???

¿Cuál es el propósito de crear un árbol de expresiones de una llamada de método solo para convertirlo en un delegado que realiza una llamada de método a la que usted llama? ¿Por qué no llamar simplemente a SomeClass.Create directamente?

¿Hay algo que me estoy perdiendo aquí?

Para responder a su pregunta actual:

¿Cómo incorporo el reparto también antes de la compilación?

Use Expression.Convert() para crear un nodo de árbol de expresión que represente una conversión.



Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow