Question

I recently saw an example where the following was demonstrated to work:

T Add<T>(dynamic a, dynamic b)
{
    return a + b;
}

Add<string>("hello", "world");  // Returns "helloworld"

However, if I were to attempt to use expressions to create a "generic" Add function:

ParameterExpression left = Expression.Parameter(typeof(T), "left");
ParameterExpression right = Expression.Parameter(typeof(T), "right");
var add = Expression.Lambda<Func<T, T, T>>(Expression.Add(left, right), left, right).Compile();  // Fails with System.InvalidOperationException : The binary operator Add is not defined for the types 'System.String' and 'System.String' when T == String.

and then used this function with strings, it fails because the String type does not actually implement the + operator, but is simply syntactic sugar for String.Concat().

How then, does dynamic allow this to work? I figured that at runtime it is past the point where + would be rewritten using String.Concat().

Was it helpful?

Solution

dynamic uses runtime helper functions that replicate C# compiler rules. One of these rules allows + on string objects even when no operator is defined by the framework. The standard numeric types such as int have no custom operator overload either, that too is done by the compiler and needs to be performed at runtime when using dynamic. This is why you need a reference to Microsoft.CSharp.dll: dynamic cannot work without those helper functions.

OTHER TIPS

Based on the documentation, maybe instead of Expression.Add(left, right) you could say Expression.Add(left, right, method) where method is the MethodInfo of the static String.Concat(String, String).

var method = typeof(string).GetMethod("Concat", new[] { typeof(string), typeof(string), });

EDIT: Hmm, my answer sort of misses the point. The interesting question is: What operations does the runtime consider when it tries to resolve a + that the compiler has let through without type-checking? Bulit-in addition for numeric types? String concatenation? Delegate concatenation? User-defined operator overloads?

In your first example a and be are still strings (try this):

// Define other methods and classes here
T Add<T>(dynamic a, dynamic b)
{
    Console.WriteLine(a.GetType());
    Console.WriteLine(b.GetType());
    return a + b;
}

Maybe this makes more sense?

void Main()
{
var x = Add<string>(new { val = "hello"},new { val = "world"});  // Returns "hello world"  
Console.WriteLine(x);
}

// Define other methods and classes here
T Add<T>(dynamic a, dynamic b)
{
    return a.val + b.val;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top