2012-03-07 21 views
45

Biorąc pod uwagę następujące metody:Jak ustawić wartość właściwości za pomocą wyrażeń?

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); 
} 

Jak byś go o pisanie to wyrażenie włączona odpowiednik bez konieczności przechodzić na dodatkowym parametrem do celu?

Dlaczego to zamiast ustawiać właściwość bezpośrednio, słyszę, jak mówisz. Na przykład załóżmy, że mamy następujące klasy z nieruchomości, która ma publiczną getter ale prywatny setter:

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

chciałbym móc zadzwonić:

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

Teraz Oto przykładowy kod.

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 

} 

Jakieś wskazówki?

+0

Dlaczego chcesz to zrobić? Jeśli nieruchomość ma prywatnego ustawiacza, to nie powinna być zmieniana z zewnątrz obiektu! Proponowana przez ciebie funkcja łamie semantykę twojego programu. –

+1

@ VladislavZorov Widziałem taki komentarz, a ja podzielam twój pogląd. W tym przypadku DTO strony trzeciej musi zostać przygotowany na test jednostkowy i byłoby to najprostsze podejście. Refleksja ma również swoje zastosowania. – Anastasiosyal

+0

możliwy duplikat [Jak ustawić wartość selektora właściwości Wyrażenie >] (http://stackoverflow.com/questions/8107134/how-set-value-a-property-selector-expressionfunct-tresult) http: // stackoverflow.com/questions/5075484/property-selector-expressionfunct-how-to-get-value-to-selected-property – nawfal

Odpowiedz

91

Można oszukiwać i ułatwić życie z metodę rozszerzenia:

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); 
      } 
     } 
    } 
} 

, a następnie:

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

Powodem tego jest łatwiejsze jest bo masz już cel na której rozszerzenie metoda jest wywoływana. Również wyrażenie lambda jest prostym wyrażeniem członu bez zamknięć. W twoim oryginalnym przykładzie cel jest przechwytywany w zamknięciu i może być nieco trudnym, aby dostać się do podstawowego celu i PropertyInfo.

+0

+1 Dziękuję za wzmiankę o zamknięciu, zastanawiałeś się, co tam robi FieldExpression. Oznaczałoby to, że wartość może być osiągnięta przez zupełnie nie elegancki: '((memberSelectorExpression.Expression jako MemberExpression) .Expression jako ConstantExpression) .Value' w celu uzyskania wartości zamkniętego pola. Lubię twoje podejście, dodając ogólną metodę rozszerzenia. – Anastasiosyal

+1

Wygląda na to, że coś jest nie tak. Właściwość się nie zmienia, a prosta rzut rzuca wyjątek: 'Nie można rzutować obiektu typu" System.Linq.Expressions.UnaryExpression ", aby wpisać" System.Linq.Expressions.MemberExpression ". – Stijn

+14

Property.SetValue to odbicie . Nie powinieneś tego używać. – MBoros

Powiązane problemy