I have an object with over 100 properties. I then have a list with a lot of these objects. I need to calculate the Min, Max, Medium and Median on all the properties in the list.
So instead of writing:
Ag = _valuesForExtraCalculations.Min(c => c.Ag),
Al = _valuesForExtraCalculations.Min(c => c.Al),
Alkal = _valuesForExtraCalculations.Min(c => c.Alkal),
one hundred times, I thought I would be able to use reflection, so I wrote:
var Obj = new Analysis();
Type t = Obj.GetType();
PropertyInfo[] prop = t.GetProperties();
foreach (var propertyInfo in prop)
{
propertyInfo = _valuesForExtraCalculations.Min(?????);
}
But I'm not sure what to write in the foreach loop, so I can set the new min value for that property to the new Analysis object I created.
As far as I've understood your question, you can achieve this using expressions:
/// <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]; }
}
}
Usage:
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));
}
}
Compiled lambdas work faster than reflection, and there will be no boxing/unboxing.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With