Alberi di espressione, oggetto di confronto

c# expression-trees

Domanda

Ho bisogno di generare albero delle espressioni che controlli due oggetti (argomenti) per l'uguaglianza. So che questi oggetti avranno proprietà, quindi devo confrontare i loro valori, come farlo? Quindi ho qualcosa come obj1 , obj2 e array di stringhe con nomi di proprietà che ho bisogno di controllare. Ecco come vedo questo:

var leftObject = E.Parameter(typeof (object), "leftObject");
var rightObject = E.Parameter(typeof (object), "rightObject");
var properties = E.Parameter(typeof (string[]), "properties");
var i = E.Parameter(typeof(int), "i");
var equal = E.Parameter(typeof (bool), "equal");

var body = E.Block
    (
        new[] { properties, i},
        E.Assign(properties,E.Constant(props)),
        E.Assign(i,E.Constant(0)),
        E.Assign(equal,E.Constant(true)),

        E.Loop
        (
            E.Property(leftObject,props[i]) == E.Property(rightObject,props[i])
        )
    );

Come implementare l'accesso alle proprietà una per una in Loop?

PS E è il mio alias per Expression .

Risposta accettata

Dovresti usare la riflessione per scoprire le proprietà che vuoi, quindi creare fondamentalmente una grande serie di espressioni AndAlso. per esempio

    public static Func<T, T, bool> BuildStructuralComparerDelegate<T>() where T:class
    {
        var left = Expression.Parameter(typeof(T), "left");
        var right = Expression.Parameter(typeof(T), "right");
        var referenceEquals = typeof(object).GetMethod("ReferenceEquals");
        Expression expression = Expression.AndAlso(
            Expression.Not(
                Expression.Call(
                    null,
                    referenceEquals,
                    left,
                    Expression.Default(typeof(T))
                )
            ),
            Expression.Not(
                null,
                Expression.Call(
                    referenceEquals,
                    right,
                    Expression.Default(typeof(T))
                )
            )
        );
        Array.ForEach(typeof(T).GetProperties(),property =>
            expression = Expression.AndAlso(
                expression,
                Expression.Equal(
                    Expression.Property(left, property),
                    Expression.Property(right, property)
                )
            )
        );
        var lambdaExp = Expression.Lambda<Func<T, T, bool>>(
            Expression.OrElse(
                Expression.Call(
                    null,
                    referenceEquals,
                    left,
                    right
                ),
                expression
            ),
            left,
            right
        );
        return lambdaExp.Compile();
    }

Il codice sopra funziona solo sulle classi, crea un'espressione approssimativamente

(left,right)=> object.ReferenceEquals(left,right) || (left != null && right != null && left.Property1 == right.Property1 && left.Property2 == right.Property2 && ... && left.PropertyN == right.PropertyN);

Non è una soluzione completa in quanto presuppone di voler confrontare tutte le proprietà e tutte le proprietà sono leggibili, ma dovrebbe portarti sul percorso. È anche compatibile con .NET 3.5 se ti interessano queste cose.




Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché
Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché