This isn't specific to dynamic
. You will get the same result if you replace dynamic
with object
. You would even get that for custom value types that implement an interface and you want to return them from a Func<IImplementedInterface>
.
The reason for this is the fact that when you want to return an int
as object
it has to be boxed - as you correctly guessed.
The expression that is used for boxing is Expression.Convert
. Adding that to your code will fix the exception:
private static Expression<Func<T, dynamic>> BuildDynamicExpression<T>(
T arg,
MethodInfo method)
{
ParameterExpression param = Expression.Parameter(typeof(T));
var methodCall = Expression.Call(param, method);
var conversion =
return Expression.Lambda<Func<T, dynamic>>(
Expression.Convert(methodCall, typeof(object)),
new ParameterExpression[] { param });
}
BTW: As you can see, I removed the args
array. It is not necessary.
To work around the problem with Moq I think you need to change the approach a bit.
The idea is the following:
- Create an expression with the exact return type of the called method.
- Let the DLR (Dynamic Language Runtime) figure out the type of the expression.
In Code:
IEnumerable<Expression> results =
typeof(ITestCase2).GetMethods()
.Select(m => BuildDynamicExpression(
new TestCase2Impl(), m));
BuildDynamicExpression
looks like this:
private static Expression BuildDynamicExpression<T>(T arg, MethodInfo method)
{
ParameterExpression param = Expression.Parameter(typeof(T));
return Expression.Lambda(Expression.Call(param, method),
new ParameterExpression[] { param });
}
Usage would be like this:
foreach(var expression in results)
{
mock.Setup((dynamic)expression);
// ...
}
The important part here is the cast to dynamic
before passing the expression to Setup
.