Árbol de expresiones: evitar DynamicInvoke

c# delegates expression-trees

Pregunta

Yo uso árboles de expresiones para construir delegados en tiempo de ejecución:

Type type = GetType();
ParameterExpression parameterType = Expression.Parameter(type);
...
Delegate delegate = Expression.Lambda(*something*, parameterType).Compile();

No sé en el momento de la compilación el tipo devuelto por el método GetType (). ¿Es posible invocar a mi delegado sin usar el costoso método DynamicInvoke ()?

Editar:

En mi aplicación tengo una clase abstracta de base:

public abstract class Frame
{
    public string RawContent { get; set; }

    // ...
}

En tiempo de ejecución, la aplicación utilizará algunos objetos que heredan Frame; el tipo de estos objetos no se conoce en el momento de la compilación, ya que se cargarán con MEF (complementos). El objetivo de la aplicación es filtrar los objetos con datos erróneos: por ejemplo, si el programa debe procesar algunos objetos de una clase como esta:

public class Frame01 : Frame
{
    public int Counter6hours { get; set; }

    public int DeltaCounter6hours { get; set; }
}

Me gustaría que mis usuarios puedan escribir, en el archivo de configuración de la aplicación, algo como esto:

<filtersSection>
    <filters>
            <filter class="Frame01" expression="Counter6hours < 0" />
            <filter class="Frame01" expression="DeltaCounter6hours > 2500" />
    </filters>
<filtersSection>

Puedo crear un árbol de expresiones y compilarlo en un delegado para cada filtro. Pero no puedo convertirlo en Func porque no conozco el tipo Frame01 en tiempo de compilación ... Entonces, por el momento, utilizo el método DynamicInvoke () de mis delegados, que invoca de forma tardía al métodos subyacentes. La aplicación tendrá que manejar una gran cantidad de objetos, y me temo que hay problemas de rendimiento ... Entonces, en este ejemplo, estoy tratando de construir mediante programación un objeto Func, pero no estoy seguro de que sea posible.

PD: disculpe por mi pobre ingles ...

Respuesta aceptada

Aún no está del todo claro para mí, esto es lo que quiere, pero creo que todo lo que necesita es una conversión: su expresión tendrá un parámetro de tipo Frame , lo Frame01 en Frame01 y luego ejecutará sus filtros en eso.

En codigo:

var type = typeof(Frame01);

var param = Expression.Parameter(typeof(Frame));
var casted = Expression.Convert(param, type);

// this part will be dynamic in your actual code
var condition = Expression.LessThan(
    Expression.Property(casted, "Counter6hours"), Expression.Constant(0));

var result = Expression.Lambda<Func<Frame, bool>>(condition, param)
    .Compile();

Con eso, pasan las siguientes pruebas:

Assert.IsTrue(result(new Frame01 { Counter6hours = -1 }));
Assert.IsFalse(result(new Frame01 { Counter6hours = 1 }));
Assert.Throws<InvalidCastException>(() => result(new Frame02()));

Respuesta popular

De tus comentarios, quieres terminar con un Func<object, bool>

Entonces, tienes que construir tu árbol de expresiones tomando un parámetro de tipo object

Algo como esto funcionará:

var p = Expression.Parameter(typeof(object));
var c = Expression.Constant(true);
var lambda = Expression.Lambda(c,p);
var fn = ( Func<object, bool> ) lambda.Compile();

Entonces:

bool b = fn( ...some object... );


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