views:

64

answers:

2

In our application we have number of AggregatorTypes (idea copied from SQL Server) i.e. MinAggregator MaxAggregator, CountAggregator, And SumAggregator.

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.

+1  A: 

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.

Marc Gravell
Can I expect that if Type implements + and - operators it is summable.
Sergey Mirvoda
@Sergey - with the implementation cited above, yes: adding + is enough to make it summable (although it also supports the inbuilt types like `int` which *don't* (as explained) truly have operators). Adding + and a /(int) would make it possible to use `Average`.
Marc Gravell
hm, but what to do with simple types as short, byte, uint, long etc?
Sergey Mirvoda
@Sergey - If you use the MiscUtil code, it handles them for you. The code is available for download, so you can see how it does it, or it is discussed on the "as discussed here" page.
Marc Gravell
@Marc Gravell thank you for info about lifted operators I never expect such a thing typeof(IComparable).IsAssignableFrom(typeof(int?))==false.now my dynamic comparer uses Comparer<T>var type = typeof (int?);int f = 0;int? s = 0;var comparer = typeof(Comparer<>).MakeGenericType(type);var d = comparer.GetProperty("Default").GetValue(null, BindingFlags.Static, null, null, null);var equals = comparer.GetMethod("Compare").Invoke(d, new object[] {f, s})==0;
Sergey Mirvoda
@Sergey - that will be slow as treacle; if you don't know the type, use the non-generic `Comparer.Default.Compare(x,y)`. And for equals, just use `object.Equals(x,y)`
Marc Gravell
A: 

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 devideExpression = Expression.Divide(paramA, conv);
        // compile it
        var add = Expression.Lambda(addExpression, paramA, paramB).Compile();
        var devide = Expression.Lambda(devideExpression, paramA, avg).Compile();
        var v = Activator.CreateInstance(type);
        add.DynamicInvoke(v, v);
        devide.DynamicInvoke(v, 1);
                    return true;
}
catch
{
  return false;
}
}

part of the code taken from MiscUtil by Marc Gravell

Sergey Mirvoda