3

I have an ExpandoObject with an int field, and I want to cast it to a decimal using an expression tree.

Here is the method I'm using :

private static Expression<Func<dynamic, decimal>> CreateLambdaCastExpression()
    {
        // source
        var sourceParameterExpression = Expression.Parameter(typeof (object), "source");

        var binder = Binder.GetMember(
            CSharpBinderFlags.None, "IntProp", typeof (ExpressionTreeUtils),
            new[] {CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null)});
        // source.sourceProperty
        var sourcePropertyExpression = Expression.Dynamic(
            binder, typeof (object), sourceParameterExpression);

        // (decimal) source;
        var castedValueExpression = Expression.Convert(sourcePropertyExpression, typeof (decimal));

        // () =>  (decimal) source;
        return Expression.Lambda<Func<dynamic, decimal>>(castedValueExpression,
            sourceParameterExpression);
    }

Calling it this way causes an InvalidCastException:

        dynamic source = new ExpandoObject();
        source.IntProp = 1;

        decimal r = CreateLambdaCastExpression().Compile()(source);

If I set source.IntProp to 1m, it works (obviously)

I've read on msdn that ExpressionConvert only performs implicit conversion on user-defined types, so that might be the explanation.

Any idea on how to perform implicit casts on numeric types?

xanatos
  • 109,618
  • 12
  • 197
  • 280
Brann
  • 31,689
  • 32
  • 113
  • 162
  • Not sure I got this fully. But I believe the `Expression.Convert` follows "the implementing method is `null`" as "`expression.Type` is a reference type". It is `object`. So probably if it is `var sourcePropertyExpression = Expression.Dynamic( binder, typeof (int), sourceParameterExpression);` it would help. – Artyom Aug 15 '15 at 11:57

1 Answers1

3

Change these lines:

// CSharpBinderFlags.ConvertExplicit: explicit cast 
// (will convert double to decimal)
// CSharpBinderFlags.None: implicit cast
// (will convert int to decimal, won't convert double to decimal)
var convert = Binder.Convert(CSharpBinderFlags.ConvertExplicit, typeof(decimal), typeof(ExpressionTreeUtils));

// (decimal) source;
var castedValueExpression = Expression.Dynamic(
    convert, typeof(decimal), sourcePropertyExpression);

Note the comment about implicit/explicit casting.

(so the only thing that changes is how the var castedValueExpression is built)

ideone with full example.

xanatos
  • 109,618
  • 12
  • 197
  • 280