• 用dynamic增强C#泛型表达力


    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)

  • 相关阅读:
    C#如何从普通C++动态库导入一个类?
    MFC的子类化技术
    [转贴] 不要以为使用了模式就是好设计
    VC编程经验汇总(三)
    钩子技术介绍及函数使用
    关于VC中的时间函数讨论
    my read_girl
    Linux + SVN / CVS / ClearCase
    OS + Linux Edit emacs /vi vim gvim /SciTE /gedit /kedit /UltraEdit /nedit /sedf
    java Regular Expression / regexp / zhengzebiaodashi
  • 原文地址:https://www.cnblogs.com/weidagang2046/p/1883032.html
Copyright © 2020-2023  润新知