The binary operator Multiply is not defined for the types 'System.Int32' and 'System.Double'.
Asked Answered
N

4

11

Why the following code throws an exception at runtime, whereas doing it in the traditional way compiles without problem?

var left = Expression.Constant(25d);
var right = Expression.Constant(20);

// Throws an InvalidOperationException!
var multiplyExpression = Expression.Multiply(left, right); 

var multiply = 25d * 20;
Debug.WriteLine(multiply.ToString()); // Works normally!

I won't use Expression.Convert since I can't determine exactly which expression should be converted.

Nucleotide answered 30/7, 2011 at 15:29 Comment(3)
Because in the traditional way, the compiler inserts the (moral equivalent of) an Expression.Convert - using type precedence rules to determine which side to convert.Zea
Which expression would the C# compiler have converted in this case?Damal
Just check the type of "multiply", that will tell you which side needs converted.Satin
N
9

Well, I figured out how to solve the problem using TypeCode enumeration to determine which node would have higher type precision, then convert the latter node's type to the former's type, and vice versa:

  private static void Visit(ref Expression left, ref Expression right)
  {
     var leftTypeCode = Type.GetTypeCode(left.Type);
     var rightTypeCode = Type.GetTypeCode(right.Type);

     if (leftTypeCode == rightTypeCode)
         return;

     if (leftTypeCode > rightTypeCode)
        right = Expression.Convert(right, left.Type);
     else
        left = Expression.Convert(left, right.Type);
  }
Nucleotide answered 30/7, 2011 at 21:12 Comment(1)
Oh dam... TypeCode isn't available on Windows Store. so close... ;(Shih
L
8
var left = Expression.Constant(25d);
var right = Expression.Constant(20);
var multiplyExpression = Expression.Multiply(
    left, 
    Expression.Convert(right, left.Type)); 

Or, if you don't know that the left side has higher precision, and you want to always end up with a double result, you could say something like:

Expression left = Expression.Constant(2);
Expression right = Expression.Constant(25.1);
left = Expression.Convert(left, typeof(double));
right = Expression.Convert(right, typeof(double));
var multiplyExpression = Expression.Multiply(left, right); 
Latrell answered 30/7, 2011 at 16:18 Comment(2)
Well, this looks good, but how could this be done if the operands are of type float, decimal?Nucleotide
@Islam Ibrahim: There are a number of possibilities, and it's usually best to go with the simplest strategy that will work for your purposes. Perhaps if you share more information on your requirements, and what this is used for, we could help you find a solution to match. For example, do you know what type you want to end up with ahead of time, or will that change depending on the inputs?Latrell
G
0

Well the error message in your title is telling you why there is an exception.

There is no Expression.Multiply method defined which takes a System.Int32 and a System.Double as arguments.

The * will work because it's lower level and your values will be type cast automatically.

Garth answered 30/7, 2011 at 15:37 Comment(0)
C
0
var left = Expression.Constant(25d);
var right = Expression.Constant((double)20);

var multiplyExpression = Expression.Multiply(left, right); // works
Crimea answered 30/7, 2011 at 15:58 Comment(1)
This can't be done directly, I should call Expression.Convert somehow.Nucleotide

© 2022 - 2024 — McMap. All rights reserved.