我最近看到了一个示例,证明以下内容有效:
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()重写+的点。
答案 0 :(得分:6)
dynamic
使用复制C#编译器规则的运行时辅助函数。即使框架未定义任何运算符,其中一条规则也允许在+
个对象上string
。诸如int
之类的标准数字类型也没有自定义运算符重载,这也是由编译器完成的,并且在使用dynamic
时需要在运行时执行。这就是您需要对Microsoft.CSharp.dll的引用的原因:dynamic
在没有这些帮助函数的情况下无法工作。
答案 1 :(得分:3)
根据文档,也许代替Expression.Add(left, right)
您可以说Expression.Add(left, right, method)
其中method
是静态MethodInfo
的{{1}}。
String.Concat(String, String)
编辑:嗯,我的答案有点忽略了这一点。有趣的问题是:当运行时尝试解析编译器在没有类型检查的情况下通过的var method = typeof(string).GetMethod("Concat", new[] { typeof(string), typeof(string), });
时,运行时会考虑哪些操作? Bulit-另外还有数字类型?字符串连接?委托连接?用户定义的运算符重载?
答案 2 :(得分: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;
}