2012-05-16 46 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表达式工作得更快,然后反思,就没有拳击/拆箱。