In our application we have number of AggregatorTypes (idea copied from SQL Server) i.e. MinAggregator MaxAggregator, CountAggregator, And SumAggr开发者_如何学Pythonegator.
Now I should check if Aggregator supports type of provided values. For Count it is not important. For Max and Min I use checking for IComparable. But what to use for SUM? I tried Converter but it also supports string.
Why there is no ISummable :)
Also IsNumeric like checking is not a solution for me. For example TimeSpan also can sum.
Actually, for min/max it is easier to use Comparer<T>.Default
, which also supports IComparable<T>
, handles "lifted" operators, etc.
You can get most of this for free if you use MiscUtil; I wrote some code that provides access to generic operators, including generic extension methods for Sum
, Average
, etc. Unfortunately, operators can't appear on interfaces, and to make things worse the primitives don't actually have operators in the MethodInfo
sense (this is provided directly in IL instead) - as discussed here.
Here is sample IsSummable method
public bool IsSummable(Type type)
try
{
ParameterExpression paramA = Expression.Parameter(type, "a"), paramB = Expression.Parameter(type, "b");
BinaryExpression addExpression = Expression.Add(paramA, paramB);
var add = Expression.Lambda(addExpression, paramA, paramB).Compile();
var v = Activator.CreateInstance(type);
add.DynamicInvoke(v, v);
return true;
}
catch
{
return false;
}
}
and IsAveragable function (what a weird name:) )
public bool IsAveragable(Type type)
try
{
ParameterExpression paramA = Expression.Parameter(type, "a"), paramB = Expression.Parameter(type, "b");
// add the parameters together
BinaryExpression addExpression = Expression.Add(paramA, paramB);
var avg = Expression.Parameter(typeof(int), "b");
var conv = Expression.Convert(avg,type);
BinaryExpression divideExpression = Expression.Divide(paramA, conv);
// compile it
var add = Expression.Lambda(addExpression, paramA, paramB).Compile();
var divide = Expression.Lambda(divideExpression, paramA, avg).Compile();
var v = Activator.CreateInstance(type);
add.DynamicInvoke(v, v);
divide.DynamicInvoke(v, 1);
return true;
}
catch
{
return false;
}
}
part of the code taken from MiscUtil by Marc Gravell
精彩评论