2012-03-07 41 views
45

Với phương pháp sau đây:Cách đặt giá trị thuộc tính bằng Biểu thức?

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

Làm thế nào bạn sẽ đi về cách viết nó biểu hiện kích hoạt tương đương mà không cần phải vượt qua trong một tham số bổ sung cho mục tiêu?

Tại sao điều này thay vì đặt trực tiếp thuộc tính tôi có thể nghe thấy bạn nói. Ví dụ giả sử chúng ta có lớp sau đây với một tài sản mà có một getter công cộng nhưng setter tin:

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

Tôi muốn để có thể gọi:

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

Bây giờ đây là một số mẫu mã.

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 

} 

Mọi con trỏ?

+0

Tại sao bạn muốn làm điều đó? Nếu tài sản có một setter riêng, sau đó nó không có nghĩa là phải được thay đổi từ bên ngoài đối tượng! Chức năng bạn đang đề xuất sẽ phá vỡ ngữ nghĩa của chương trình của bạn. –

+1

@VladislavZorov Tôi có thể thấy một bình luận sắp tới và tôi chia sẻ quan điểm của bạn. Trong trường hợp này, DTO của bên thứ ba cần phải được thử nghiệm trong đơn vị và đây sẽ là cách tiếp cận đơn giản nhất để thực hiện điều đó. Phản ánh cũng có sử dụng của nó. – Anastasiosyal

+0

bản sao có thể có của [Cách đặt giá trị bộ chọn thuộc tính Biểu thức >] (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

Trả lời

91

Bạn có thể lừa gạt và làm cho cuộc sống dễ dàng hơn với một phương pháp khuyến nông:

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

và sau đó:

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

Lý do tại sao điều này là dễ dàng hơn là vì bạn đã có mục tiêu trên mà phần mở rộng phương thức được gọi. Ngoài ra các biểu thức lambda là một biểu thức thành viên đơn giản mà không cần đóng cửa. Trong ví dụ ban đầu của bạn mục tiêu được chụp trong một đóng cửa và nó có thể là một chút khôn lanh để có được mục tiêu cơ bản và PropertyInfo.

+0

+1 Cảm ơn bạn đã đề cập đến việc đóng cửa, đã tự hỏi FieldExpression đang làm gì ở đó. Điều này có nghĩa là giá trị có thể đạt được bằng cách hoàn toàn không thanh lịch: '((memberSelectorExpression.Expression như MemberExpression) .Expression as ConstantExpression) .Value' để lấy giá trị của trường đã đóng. Tôi thích cách tiếp cận của bạn bằng cách thêm một phương pháp mở rộng chung. – Anastasiosyal

+1

Dường như có sự cố ở đây. Thuộc tính không thay đổi và một diễn viên thẳng ném một ngoại lệ: 'Không thể truyền đối tượng thuộc loại 'System.Linq.Expressions.UnaryExpression' để nhập 'System.Linq.Expressions.MemberExpression'.' – Stijn

+14

Property.SetValue là sự phản chiếu . Bạn không nên sử dụng nó. – MBoros

Các vấn đề liên quan