4

我最近看到了一个示例,其中演示了以下内容:

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

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

但是,如果我尝试使用表达式来创建“通用”添加函数:

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.

然后将此函数与字符串一起使用,它失败了,因为 String 类型实际上并没有实现 + 运算符,而只是 String.Concat() 的语法糖。

那么,动态如何允许它工作?我认为在运行时它已经过了使用 String.Concat() 重写 + 的点。

4

3 回答 3

6

dynamic使用复制 C# 编译器规则的运行时辅助函数。即使框架未定义任何运算符+,这些规则之一也允许对象。string标准数字类型(例如,int也没有自定义运算符重载)也是由编译器完成的,并且需要在运行时在使用dynamic. 这就是您需要引用 Microsoft.CSharp.dll 的原因:dynamic如果没有这些帮助函数,就无法工作。

于 2012-07-29T07:11:32.693 回答
3

根据文档,也许Expression.Add(left, right)您可​​以说static 的在Expression.Add(left, right, method)哪里而不是。methodMethodInfoString.Concat(String, String)

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

编辑:嗯,我的回答有点没抓住重点。有趣的问题是:运行时在尝试解析+编译器在没有类型检查的情况下允许通过的 a 时会考虑哪些操作?数字类型的内置添加?字符串连接?委托串联?用户定义的运算符重载?

于 2012-07-29T06:22:39.390 回答
0

在您的第一个示例中, a 和 be 仍然是字符串(试试这个):

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

也许这更有意义?

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;
}
于 2012-07-29T06:08:42.903 回答