[转载]用dynamic增强C#泛型表达力

[转载]用dynamic增强C#泛型表达力 – { Code Talk } – 博客园.

C++的泛型是基于模板(template)技术的。模板本身并不作为独立的编译单元,而是在编译时绑定实际参数类型进行模板实例化,类似与C语言 的宏展开,在运行时并不存在独立的模板类型。模板对泛型参数的约束是基于操作的语法特征的,属于一种静态的duck typing机制,十分灵活。

下面的代码定义了一个泛型Add函数,它对泛型参数T的要求只是支持+运算,并不要求T是某个类的子类,或是实现了某个接口。int, double, std::string等支持+运算符的类型都可以成功匹配T。

//C++

template<typename T>
T Add(const T& t1, const T& t2) {
return t1 + t2;
}

int main() {
int i = Add(1, 2);
double d = Add(1.1, 2.2);
std::string s = Add(std::string(“abc”), std::string(“def”));

std::cout << i << ” ” << d << ” ” << s << std::endl;

return 0;
}

输出:

>>3 3.3 abcdef

而类似的代码在C#中却无法编译通过:

csadd

这 是由于C#采用基于reification的泛型机制,泛型类会单独编译,并且在运行时存在;因此,C#对于泛型参数的要求更加严格,只能通过where 关键字表达基于继承关系的约束,无法通过duck typing的方式表达类型约束。与模板相比,这种机制的好处在于可以更好的支持反射和元编程,但其缺点是泛型的表达能力不如模板。幸好C#4.0中引入 了动态类型机制,我们可以通过动态类型来实现基于duck typing的泛型参数约束。

//C#

static class Calculator {
public static T Add<T>(T t1, T t2) {
dynamic d1 = t1;
dynamic d2 = t2;

return (T)(d1 + d2);
}
}

public static void Main(string[] args){
int i = Calculator.Add(1, 2);
double d = Calculator.Add(1.1, 2.2);
string s = Calculator.Add(“abc”, “def”);

Console.WriteLine(i + ” ” + d + ” ” + s);

}

输出:

>>3 3.3 abcdef

除了运算符重载,对于普通的方法调用也是适用的。这种方法是一种动态duck typing的泛型参数约束机制,依赖于运行时的方法查找,与模板编译时的检查不同,它需要使用者保证传入的对象符合相应要求。

参考:

wikipedia: Generic Programming

Dynamic Objects in C# 4.0

where (generic type constraint) (C# Reference)

赞(0) 打赏
分享到: 更多 (0)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏