2012-03-07 13 views
45

Dato il seguente metodo:Come impostare il valore della proprietà utilizzando Expressions?

public static void SetPropertyValue(object target, string propName, object value) 
{ 
    var propInfo = target.GetType().GetProperty(propName, 
         BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly); 

    if (propInfo == null) 
     throw new ArgumentOutOfRangeException("propName", "Property not found on target"); 
    else 
     propInfo.SetValue(target, value, null); 
} 

Come si va a scrivere è espressione abilitato equivalente senza bisogno di passare un parametro in più per target?

Perché farlo invece di impostare direttamente la proprietà, posso sentirti dire. Per esempio supponiamo di avere la seguente classe con una proprietà che ha un getter pubblico, ma setter privato:

public class Customer 
{ 
    public string Title {get; private set;} 
    public string Name {get; set;} 
} 

Vorrei essere in grado di chiamare:

var myCustomerInstance = new Customer(); 
SetPropertyValue<Customer>(cust => myCustomerInstance.Title, "Mr"); 

Ora qui è alcuni esempi di codice.

public static void SetPropertyValue<T>(Expression<Func<T, Object>> memberLamda , object value) 
{ 
    MemberExpression memberSelectorExpression; 
    var selectorExpression = memberLamda.Body; 
    var castExpression = selectorExpression as UnaryExpression; 

    if (castExpression != null) 
     memberSelectorExpression = castExpression.Operand as MemberExpression; 
    else 
     memberSelectorExpression = memberLamda.Body as MemberExpression; 

    // How do I get the value of myCustomerInstance so that I can invoke SetValue passing it in as a param? Is it possible 

} 

Eventuali suggerimenti?

+0

Perché vuoi farlo? Se la proprietà ha un setter privato, allora non è destinato a essere modificato dall'esterno dell'oggetto! La funzione che stai proponendo rompe la semantica del tuo programma. –

+1

@VladislavZorov Potrei vedere un tale commento arrivare e condivido il tuo punto di vista. In questo caso un DTO di terze parti ha bisogno di essere innescato in un test unitario e questo sarebbe l'approccio più semplice per farlo. Anche la riflessione ha i suoi usi. – Anastasiosyal

+0

possibile duplicato di [Come valore impostato un selettore di proprietà Espressione >] (http://stackoverflow.com/questions/8107134/how-set-value-a-property-selector-expressionfunct-tresult) http: // stackoverflow.com/questions/5075484/property-selector-expressionfunct-how-to-get-set-value-to-selected-property – nawfal

risposta

91

Si potrebbe imbrogliare e rendere la vita più facile con un metodo di estensione:

public static class LambdaExtensions 
{ 
    public static void SetPropertyValue<T, TValue>(this T target, Expression<Func<T, TValue>> memberLamda, TValue value) 
    { 
     var memberSelectorExpression = memberLamda.Body as MemberExpression; 
     if (memberSelectorExpression != null) 
     { 
      var property = memberSelectorExpression.Member as PropertyInfo; 
      if (property != null) 
      { 
       property.SetValue(target, value, null); 
      } 
     } 
    } 
} 

e poi:

var myCustomerInstance = new Customer(); 
myCustomerInstance.SetPropertyValue(c => c.Title, "Mr"); 

Il motivo per cui questo è più facile è perché avete già il bersaglio su cui l'estensione il metodo è invocato. Anche l'espressione lambda è una semplice espressione di membro senza chiusure. Nel tuo esempio originale il bersaglio viene catturato in una chiusura e potrebbe essere un po 'complicato raggiungere il target sottostante e PropertyInfo.

+0

+1 Grazie per aver menzionato la chiusura, mi chiedevo cosa stesse facendo l'espressione FieldExpression. Ciò significherebbe che il valore potrebbe essere raggiunto dal non completamente elegante: '((memberSelectorExpression.Expression come MemberExpression) .Expression as ConstantExpression) .Value' per ottenere il valore del campo chiuso. Mi piace il tuo approccio aggiungendo un metodo di estensione generico. – Anastasiosyal

+1

Sembra che ci sia qualcosa di sbagliato qui. La proprietà non cambia e un cast diretto genera un'eccezione: 'Impossibile eseguire il cast dell'oggetto di tipo 'System.Linq.Expressions.UnaryExpression' per digitare 'System.Linq.Expressions.MemberExpression'. – Stijn

+14

Property.SetValue è una riflessione . Non dovresti usare quello. – MBoros

Problemi correlati