欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

C# dynamic关键字的使用方法

程序员文章站 2023-12-14 15:59:34
c#是一种类型安全的编程语言(所有表达式都能解析成某个类型的实例,在编译器生成的代码中,只会执行对这个类型有效的操作),和非类型安全的语言相比,类型安全的优势就体现出来了:...

c#是一种类型安全的编程语言(所有表达式都能解析成某个类型的实例,在编译器生成的代码中,只会执行对这个类型有效的操作),和非类型安全的语言相比,类型安全的优势就体现出来了:
1.许多错误能在编译时检测到,取保代码在执行它之前是正确的。
2.编译时语言通常能生成更小,更快的代码。(在编译时进行更多的假设,并在il和元数据中落实那些假设)

为了方便开发人员使用反射或者与基本组件通信,dynamic诞生了!
一下代码展示了如何利用反射在一个string目标("根据我找类型")上调用一个方法(“contains”),向它传递一个实参(“我只是一个string参数”),并将结果存储到局部变量result中。

复制代码 代码如下:

static void main()
        {
            object target = "根据我找类型";
            object arg = "我只是个string参数";
            type[] argtype = new type[] { arg.gettype()};
            system.reflection.methodinfo method = target.gettype().getmethod("contains", argtype);

            object[] argm = new object[] { arg};
            boolean result=convert.toboolean(method.invoke(target,argm));
}


现在,有了dynamic!
复制代码 代码如下:

static void main()
        {
            dynamic target = "根据我找类型";
            dynamic arg = "参数";
            boolean result = target.contains(arg);
}

是不是发现有了显著的简化。
复制代码 代码如下:

static void main()
        {
            application excel = new application();
            excel.visible = true;
            excel.workbooks.add(type.missing);
            ((range)excel.cells[1, 1]).value = //www.jb51.net/smailxiaobai/archive/2011/11/25/"放入单元格的字符";//如果没有dynamic类型,excel.cells[1,1]的返回值是objec类型,必须先把它转换为rang类型才能访问value属性。
            excel.cells[1, 1].value = //www.jb51.net/smailxiaobai/archive/2011/11/25/"放入单元格的字符";//为com对象生成一个可由“运行时”调用的包装程序集时,com方法中使用的任何variant实际都会被转换为dynamic,这称为动态化(dynamicfication)。
            //所以这里excel.cells[1,1]是dynamic类型,可以不必显示把它转换成range类型也能访问它的value。动态化显著简化了与com对象的互操作。
        }

看到了dynamic的神奇,那再让我们刨根问底吧。
我们可以用dynamic表达式或变量调用一个成员,比如字段,属性/索引器,方法,委托,以及一元/二元/转换操作符,当我们的代码使用dynamic表达式或变量调用一个成员时,编译器会生成特殊的il代码来描述所需的操作。
这种特殊的代码称为payload(有效载荷)(这些payload代码使用了一个称为运行时绑定器(runtime binder)的类),在运行时,payload代码根据当前由dynamic表达式/变量引用的对象的实际类型来决定具体的操作。
看这个例子:
复制代码 代码如下:

        static void main()
        {
            for (int i = 0; i < 2; i++)
            {
                dynamic arg = (i == 0) ? (dynamic)10 : "a";
                dynamic result = plus(arg);//第一次循环i==0 ,arg=10;所以调用plus时,返回的是int类型。第二次是string类型。
                m(result);//payload代码判断出传给m的值的实际类型,然后调用相应的重载方法。
            }
          console.readkey();
        }
        static dynamic plus(dynamic arg) { return arg+arg;}
        static  void m(int n) { console.writeline("m(int):{0}", n); }
       static void m(string s) { console.writeline("m(string):{0}", s); }
    }

在字段类型,方法参数类型或方法类型被指定为dynamic的前提下,编译器会将这个类型转换为system.object,并在元数据中向字段,参数或者返回类型应用system.runtime.compilersevices.dynamicattribute的一个实例。如果是一个局部变量被指定为dynamic,变量类型也会成为object,但不会向局部变量应用dynamicattribute,应为它的使用限制在方法之内。
由于dynamic就是object 所以不仅仅将dynamic变成object,或者object变成dynamic就获取两个不同的方法签名。例子:
复制代码 代码如下:

  object dd(dynamic i) { return i; }
 dynamic dd( object i) {return i; }

这就通不过编译。
dynam的类型转换:
复制代码 代码如下:

 static void main()
        {
            object o = 123;//(装箱)
            int32 n = o;//错误!不允许从object到int32的隐式转换。
            int32 n1 = (int32)o;//从object显示转换到int32。(拆箱)

            dynamic od = 123;//(装箱)
            dynamic os = "dsfsdf";
            int32 ns = os;//运行时报错。
            int32 nd = od;//从dynamic隐式转换为int32(拆箱)
            //在本例中可看出,dynamic转为其他类型时,允许省略显示转型。
            //但是clr会在运行时验证转型,确保类型安全。如果对象类型不兼容要转换成的类型,clr就会抛出一个invalidcastexception异常。
        }


dynamic和var的区别:
1.var声明一个局部变量只是一种简化语法,它要求编译器根据一个表达式推断具体的数据类型。
2.var只能用于声明方法内部的局部变量,而dynamic可用于局部变量,字段,参数。
3.表达式不能转型为var,但能转型为dynamic。
4.必须显式初始化用var声明的变量,但无需初始化用dynam声明的变量。
使用dynamic应注意:
在运行时,microsoft.csharp.dll必须加载到appdomain中,这回损害程序性能,并增大内错耗用,microsoft.csharp.dll还会加载system.dll和system.core.dll,如果使用dynamic与com组件互操作,还会加载system.dynamic.dll,payload代码执行时会在运行时生成动态代码。这些代码会进入一个驻留在内存的程序集,称为“匿名寄宿的dynamicmethods程序集”(anonymously hosted dynamicmethods assembly).
当一个特性的调用使用具有相同运行时类型的dynamic实参发出了大量调用时,这个代码可以增强调度的性能。
虽然dynamic能简化语法,但是动态求值功能产生的额外开销也是不容忽视的,毕竟加载所有这些程序集以及额外的内存消耗,会对性能产生额外的影响。如果程序中只是一两个地方需要动态行为,或许传统的做法会更加高效。

上一篇:

下一篇: