2012-03-07 4 views
45

Учитывая следующий метод:Как установить значение свойства с помощью выражений?

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

Как бы вы идти о написании этого выражение включено эквивалентное без необходимости проходить в дополнительном параметре для цели?

Зачем это делать вместо того, чтобы напрямую устанавливать собственность, я слышу, как вы говорите. Например предположим, что мы имеем следующий класс с собственности, которая имеет публичный геттер, но частный сеттер:

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

Я хотел бы быть в состоянии назвать:

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

Теперь вот некоторые примеры кода.

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 

} 

Любые указатели?

+0

Зачем вам это нужно? Если свойство имеет собственный сеттер, то он не предназначен для изменения извне объекта! Функция, которую вы предлагаете, нарушает семантику вашей программы. –

+1

@ VladislavZorov Я мог видеть такой комментарий, и я разделяю ваше мнение. В этом случае третья сторона DTO должна быть загружена в единичный тест, и это будет самый простой способ сделать это. Отражение также имеет свои применения. – Anastasiosyal

+0

Возможный дубликат [Как заданное значение: селектор свойств Expression >] (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

ответ

91

Вы можете обмануть и сделать жизнь проще с помощью метода расширения:

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

, а затем:

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

Причина, почему это проще, потому что у вас уже есть мишень, на которой расширение метод вызывается. Кроме того, лямбда-выражение представляет собой простое выражение члена без замыканий. В вашем исходном примере цель фиксируется в закрытии, и может быть немного сложно добраться до базовой цели и PropertyInfo.

+0

+1 Спасибо за упоминание о закрытии, было интересно, что там делал FieldExpression. Это означало бы, что значение может быть достигнуто полностью не изящным: '((memberSelectorExpression.Expression как MemberExpression) .Expression as ConstantExpression) .Value', чтобы получить значение закрытого поля. Мне нравится ваш подход, добавив общий метод расширения. – Anastasiosyal

+1

Здесь, кажется, что-то не так. Свойство не изменяется, а прямая броска вызывает исключение: 'Невозможно передать объект типа 'System.Linq.Expressions.UnaryExpression' для ввода 'System.Linq.Expressions.MemberExpression' .' – Stijn

+14

Property.SetValue является отражением , Вы не должны этого использовать. – MBoros

Смежные вопросы