2012-05-16 81 views
2

我有一個超過100個屬性的對象。然後我有一個很多這些對象的列表。 我需要計算列表中所有特性的最小值,最大值,中值和中值。用反射更新列表中的值

因此,而不是寫:

Ag = _valuesForExtraCalculations.Min(c => c.Ag), 
Al = _valuesForExtraCalculations.Min(c => c.Al), 
Alkal = _valuesForExtraCalculations.Min(c => c.Alkal), 

,一個100倍,我想我將能夠使用反射,所以我寫了:

var Obj = new Analysis(); 
Type t = Obj.GetType(); 
PropertyInfo[] prop = t.GetProperties(); 
foreach (var propertyInfo in prop) 
{ 
    propertyInfo = _valuesForExtraCalculations.Min(?????); 
} 

但我不知道是什麼要在foreach循環中寫入,所以我可以將該propery的新最小值設置爲我創建的新Analysis對象。

+0

是否屬於同一類型的所有屬性? – Botz3000

+0

不,有些是字符串,但那不是主要問題,我可以隨時檢查,所以屬性是一個int,但我應該如何寫入來設置屬性? – Fore

+0

所以,你想要一個新的對象,在每個屬性中包含所有其他對象的這個屬性的平均值? – phg

回答

1

您需要知道屬性的確切類型。讓我們假設它是int

var Obj = new Analysis(); 
Type t = Obj.GetType(); 
PropertyInfo[] prop = t.GetProperties(); 
foreach (var pi in prop.Where(p => p.PropertyType == typeof(int)) 
{ 
    int min = _valuesForExtraCalculations.Min(c => (int)pi.GetValue(c, null)); 
    propertyInfo.SetValue(Obj, min, null); 
} 

如果要計算最小針對不同類型,你就不會得到解決檢查類型,並相應地切換所以Min正確的過載被調用。

我仍然不認爲這是最好的或最高性能的解決方案。

PropertyInfo.GetValuePropertyInfo.SetValue比直接字段訪問要慢(慢很多according to this article),也會涉及很多拳擊。你可以調用PropertyInfo.GetValue(countOfObjects * countOfProperties)次。根據項目和屬性的數量,這可能是值得關注的。

+0

感謝您的支持!最小值的提取工作正常,但設置正確的屬性不起作用,這部分(propertyInfo.SetValue(this,min,null);我得到的對象不匹配目標類型 – Fore

+0

@Fore我意外地插入'這個'而不是你的變量,現在編輯我的答案,如果列表中的對象和'Obj'是同一類型的,我的更新示例應該可以工作 – Botz3000

+0

工作得很好! – Fore

4

至於我明白你的問題,你可以做到這一點使用表達式:

/// <summary> 
/// A class with many-many properties 
/// </summary> 
class MyClass 
{ 
    public Decimal A { get; set; } 
    public Decimal B { get; set; } 
    public Decimal C { get; set; } 
} 

class PropertyHelper<T, TProperty> 
{ 
    private readonly Func<T, TProperty> selector; 
    private readonly Action<T, TProperty> setter; 

    public PropertyHelper(Func<T, TProperty> selector, Action<T, TProperty> setter) 
    { 
     this.selector = selector; 
     this.setter = setter; 
    } 

    public Func<T, TProperty> Selector 
    { 
     get { return selector; } 
    } 

    public Action<T, TProperty> Setter 
    { 
     get { return setter; } 
    } 
} 

class AggregateHelper<T, TProperty> 
{ 
    private readonly Dictionary<PropertyInfo, PropertyHelper<T, TProperty>> helpers; 

    public AggregateHelper() 
    { 
     this.helpers = typeof(T) 
      .GetProperties() 
      .Where(p => p.PropertyType == typeof(TProperty)) 
      .ToDictionary(p => p, p => new PropertyHelper<T, TProperty>(MakeSelector(p), MakeSetter(p))); 
    } 

    private Func<T, TProperty> MakeSelector(PropertyInfo property) 
    { 
     var parameterExpr = Expression.Parameter(typeof(T)); 
     var lambda = (Expression<Func<T, TProperty>>)Expression.Lambda(
      Expression.Property(parameterExpr, property), parameterExpr); 

     return lambda.Compile(); 
    } 

    private Action<T, TProperty> MakeSetter(PropertyInfo property) 
    { 
     var instanceExpr = Expression.Parameter(typeof(T)); 
     var parameterValueExpr = Expression.Parameter(typeof(TProperty)); 
     var lambda = (Expression<Action<T, TProperty>>)Expression.Lambda(
      Expression.Call(instanceExpr, property.GetSetMethod(), parameterValueExpr), 
      instanceExpr, 
      parameterValueExpr); 

     return lambda.Compile(); 
    } 

    public IEnumerable<PropertyInfo> Properties 
    { 
     get { return helpers.Keys; } 
    } 

    public PropertyHelper<T, TProperty> this[PropertyInfo property] 
    { 
     get { return helpers[property]; } 
    } 
} 

用法:

public static void Do() 
    { 
     var target = new MyClass(); 
     var list = new List<MyClass> 
     { 
      new MyClass { A = 1M, B = 2M, C = 3M }, 
      new MyClass { A = 10M, B = 20M, C = 30M }, 
      new MyClass { A = 100M, B = 200M, C = 300M } 
     }; 

     // calculate 'min' for all decimal properties 
     var helper = new AggregateHelper<MyClass, Decimal>(); 

     foreach (var property in helper.Properties) 
     { 
      var propertyHelper = helper[property]; 

      propertyHelper.Setter(target, list.Min(propertyHelper.Selector)); 
     } 
    } 

編譯lambda表達式工作得更快,然後反思,就沒有拳擊/拆箱。