1

Given two generic type variables, how do I compile a system.linq.expression tree to multiply them? It's perfectly acceptable if the expression throws an exception if the two types do not have a valid operator * between them.

I chose System.Linq.Expression because I recall seeing it done that way on here, but not enough about how.

Thanks.

Edit: I chose compiling a Linq expression for speed; this should be as fast as reasonably possible.

Narf the Mouse
  • 1,541
  • 5
  • 18
  • 30

3 Answers3

4

You can find out how to do this by writing the following code:

Expression<Func<int, int, int>> multiply = 
    (left, right) => left * right;

Compiling it down to an assembly and use a IL deassembler (such as Reflector) to look at the code the C# compiler produced.

With the given example, the C# compiler will generate something like this:

var left = Expression.Parameter(typeof(int), "left");
var right = Expression.Parameter(typeof(int), "right");

var multiply = Expression.Lambda<Func<int, int, int>>(
    Expression.Multiply(left, right),
    new ParameterExpression[] { left, right });

And this is exactly what you need to do to specify a multiply expression.

When placed in a generic method, it might look something like this:

public static Func<T, T, T> BuildMultiplier<T>()
{
    var left = Expression.Parameter(typeof(T), "left");
    var right = Expression.Parameter(typeof(T), "right");

    var multiply = Expression.Lambda<Func<T, T, T>>(
        Expression.Multiply(left, right),
        new ParameterExpression[] { left, right });

    return multiply.Compile();
}
Steven
  • 166,672
  • 24
  • 332
  • 435
2

Try something like this:

var left = Expression.Parameter(typeof(T), "left");
var right = Expression.Parameter(typeof(T), "right");
var body = Expression.Multiply(left, right);
return Expression.Lambda<Func<T, T, TResult>>(body, left, right);

If there is no valid multiplication operator for type T, the Expression.Multiply line will throw an exception.

Richard Deeming
  • 29,830
  • 10
  • 79
  • 151
2

I chose System.Linq.Expression

Just to be clear: there's another easy way:

public static T Multiply<T>(T x, T y) {
    return ((dynamic)x) * y;
}

and offload the work (including cache) to the framework. Another option - MiscUtil has generic operator support that wraps this up - downloadable here.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • Problem with that is, dynamic is slow. I need this to be fast, hence compiling. Sorry, I'll add that to the requirements. – Narf the Mouse Oct 30 '12 at 20:40
  • @Narf not necessarily as slow as you think, due to cache of the generated IL. Have you measured it? I seem to recall having done so in the past, and certainly for non-nullable types it was surprisingly fast. – Marc Gravell Oct 30 '12 at 20:42
  • I did test it in the past. I should probably do more tests. – Narf the Mouse Oct 30 '12 at 21:38