come creare albero di espressione / lambda per una proprietà profonda da una stringa

c# expression-trees lambda

Domanda

Data una stringa: "Person.Address.Postcode" Voglio essere in grado di ottenere / impostare questa proprietà del codice postale su un'istanza di Person. Come posso fare questo? La mia idea era di dividere la stringa con "." e quindi scorrere le parti, cercando la proprietà sul tipo precedente, quindi creare un albero di espressioni che assomiglierebbe a qualcosa (scuse per la pseudo sintassi):

(person => person.Address) address => address.Postcode

Ho davvero dei problemi a creare acutalmente l'albero delle espressioni! Se questo è il modo migliore, qualcuno può suggerire come procedere, oppure esiste un'alternativa più semplice?

Grazie

Andrea

public class Person
{
    public int Age { get; set; }
    public string Name { get; set; }
    public Address Address{ get; set; }

    public Person()
    {
        Address = new Address();
    }
}

public class Address 
{
    public string Postcode { get; set; }
}

Risposta accettata

Perché non usi la ricorsione? Qualcosa di simile a:

setProperyValue(obj, propertyName, value)
{
  head, tail = propertyName.SplitByDotToHeadAndTail(); // Person.Address.Postcode => {head=Person, tail=Address.Postcode}
  if(tail.Length == 0)
    setPropertyValueUsingReflection(obj, head, value);
  else
    setPropertyValue(getPropertyValueUsingReflection(obj, head), tail, value); // recursion
}

Risposta esperta

Sembra che tu sia ordinato con una riflessione regolare, ma per informazioni, il codice per creare un'espressione per le proprietà nidificate sarebbe molto simile a questo codice order-by .

Si noti che per impostare un valore, è necessario utilizzare GetSetMethod() sulla proprietà e invocare ciò: non esiste un'espressione incorporata per l'assegnazione di valori dopo la costruzione (sebbene sia supportata in 4.0 ).

(modifica) in questo modo:

using System;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
class Foo
{
    public Foo() { Bar = new Bar(); }
    public Bar Bar { get; private set; }
}
class Bar
{
    public string Name {get;set;}
}
static class Program
{
    static void Main()
    {
        Foo foo = new Foo();
        var setValue = BuildSet<Foo, string>("Bar.Name");
        var getValue = BuildGet<Foo, string>("Bar.Name");
        setValue(foo, "abc");
        Console.WriteLine(getValue(foo));        
    }
    static Action<T, TValue> BuildSet<T, TValue>(string property)
    {
        string[] props = property.Split('.');
        Type type = typeof(T);
        ParameterExpression arg = Expression.Parameter(type, "x");
        ParameterExpression valArg = Expression.Parameter(typeof(TValue), "val");
        Expression expr = arg;
        foreach (string prop in props.Take(props.Length - 1))
        {
            // use reflection (not ComponentModel) to mirror LINQ 
            PropertyInfo pi = type.GetProperty(prop);
            expr = Expression.Property(expr, pi);
            type = pi.PropertyType;
        }
        // final property set...
        PropertyInfo finalProp = type.GetProperty(props.Last());
        MethodInfo setter = finalProp.GetSetMethod();
        expr = Expression.Call(expr, setter, valArg);
        return Expression.Lambda<Action<T, TValue>>(expr, arg, valArg).Compile();        

    }
    static Func<T,TValue> BuildGet<T, TValue>(string property)
    {
        string[] props = property.Split('.');
        Type type = typeof(T);
        ParameterExpression arg = Expression.Parameter(type, "x");
        Expression expr = arg;
        foreach (string prop in props)
        {
            // use reflection (not ComponentModel) to mirror LINQ 
            PropertyInfo pi = type.GetProperty(prop);
            expr = Expression.Property(expr, pi);
            type = pi.PropertyType;
        }
        return Expression.Lambda<Func<T, TValue>>(expr, arg).Compile();
    }
}


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é