l33t
l33t

Reputation: 19966

Explicit cast in expression tree?

Consider the MyDecimal class below. In C# we can cast it to an integer thanks to the implicit decimal operator:

int i = (int)new MyDecimal(123m);

How do you produce the equivalent code in an expression tree?

When using Expression.Convert (.NET 4.5.1) it immediately fails with No coercion operator is defined between types 'System.Int32' and 'MyDecimal'. It seems to only consider implicit cast operators.

try
{
    var param = Expression.Parameter(typeof(int), null);
    var convert = Expression.Convert(param, typeof(MyDecimal));
}
catch (Exception ex)
{
}

MyDecimal class:

public class MyDecimal
{
    private readonly decimal value;

    public MyDecimal(decimal value)
    {
        this.value = value;
    }

    public static implicit operator decimal(MyDecimal myDecimal)
    {
        return myDecimal.value;
    }

    public static implicit operator MyDecimal(decimal value)
    {
        return new MyDecimal(value);
    }
}

Upvotes: 4

Views: 1520

Answers (1)

kͩeͣmͮpͥ ͩ
kͩeͣmͮpͥ ͩ

Reputation: 7846

It's always interesting to example the expression tree of an Expression Lambda that does the same thing:

Expression<Func<MyDecimal,int>> convert = m => (int)m;

Using a tool link LinqPad we can examine convert and see we have the following:

Expression<Func<MyDecimal,int>> (type: Lambda)
|
+-  UnaryExpression (type:Convert) - Convert(int, decimal)
    |
    +- UnaryExpression (type:Convert) - Convert(decmal, MyDecimal)

So, although the compiler allows the implicit conversion from decimal to int, you can see that the equivalent Lambda requires the conversion to be explicit.

EDIT

So, to construct the complete expression, you've have something like:

        Expression.Assign(
            Expression.Variable(typeof(int), "i"),
            Expression.Convert(
                Expression.Convert(
                    Expression.New(
                        typeof(MyDecimal).GetConstructor(new[] {typeof(decimal)}),
                        Expression.Convert(
                            Expression.Constant(1),
                            typeof(decimal)
                        )
                    ),
                    typeof(decimal)),
                typeof(int)
            )
        )

Some points to note:

  • We're converting the int 1 to decimal to pass to the constructor
  • We have to look up the constructor with the correct type parameters (I'm cheating and assuming it's public)
  • We're assuming i is already declared.

Upvotes: 4

Related Questions