C# dynamic关键字的使用方法
发布时间:2023-02-26 08:40:01
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 = https://www.jb51.net/smailxiaobai/archive/2011/11/25/"放入单元格的字符";//如果没有dynamic类型,excel.Cells[1,1]的返回值是objec类型,必须先把它转换为Rang类型才能访问Value属性。
excel.Cells[1, 1].Value = https://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能简化语法,但是动态求值功能产生的额外开销也是不容忽视的,毕竟加载所有这些程序集以及额外的内存消耗,会对性能产生额外的影响。如果程序中只是一两个地方需要动态行为,或许传统的做法会更加高效。
猜你喜欢
- 最近在做项目时需要对异常进行全局统一处理,主要是一些分类入库以及记录日志等,因为项目是基于Springboot的,所以去网络上找了一些博客文
- Feign导入依赖为unknow的情况网上很多人在使用的feign时在pom.xml中的依赖为:<!-- SpringCloud 整合
- 本文实例为大家分享了C#实现截图工具小项目的具体代码,供大家参考,具体内容如下1.起因一直用的截图是qq的截图,所以想要实现一个简单点的截图
- 大家可以自行百度下阿里分布式事务,在这里我就不啰嗦了。下面是阿里分布式事务开源框架的一些资料,本文是springboot+dubbo+fes
- Stream流常见的中间操作方法Streamfilter(Predicate predicate):用于对流中的数据进行过滤predicat
- 本文实例为大家分享了Unity实现攻击范围检测并绘制检测区域的具体代码,供大家参考,具体内容如下一、圆形检测using System.Col
- 前言图文并茂的内容往往让人看起来更加舒服,如果只是文字内容的累加,往往会使读者产生视觉疲劳。搭配精美的文章配图则会使文章内容更加丰富,增加文
- 本文实例形式展示了C#中异步调用的实现方法,并对其原理进行了较为深入的分析,现以教程的方式分享给大家供大家参考之用。具体如下:首先我们来看一
- 0、线程的本质线程不是一个计算机硬件的功能,而是操作系统提供的一种逻辑功能,线程本质上是进程中一段并发运行的代码,所以线程需要操作系统投入C
- 对于java开发人员来说,Idea的普及率已经很高了。但是还是很多好用的技巧没有用到,只是用到一些基本的功能,蛮浪费IDEA这个优秀的IDE
- 问题描述:图片加载后显示,然后进行删除操作时提示“……正由另一进程使用,因此该进程无法访问该文件。……”解决办法:原代码:iml.Image
- protected bool IsChineseLetter(string input,int index){int code = 0;in
- 0.引言死信队列是消息队列中非常重要的概念,同时我们需要业务场景中都需要延迟发送的概念,比如12306中的30分钟后未支付订单取消。那么本期
- 一、题目描述题目实现:不同的客户端之间需要进行通信,一个客户端与指定的另一客户端进行通信,实现一对一聊天功能。实现一个客户端与指定的另一客户
- 举个例子Map < String , Object > jsonMap = new HashMap< String , O
- 一、概述在软件开发中,有时需要保存一个对象的状态,以便于允许用户取消相关操作或者从以往的状态中恢复过来。比如一个文档版本管理系统,可以根据需
- 1. 简介Jpa 是一套ORM 的规范hibernate 不就是一个 ORM 框架也提供了对于 JPA 的实现JPA(Java Persis
- 一、前言:垃圾回收:在未来的JDK中可能G1会为ZGC所取代先问自己几个问题:什么是垃圾?垃圾就是堆内存中(范指)没有任何指针指向的对象实体
- 这篇文章主要介绍了Spring MVC4.1服务器端推送实现过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习
- 一、Java的前世为什么会产生Java?Java的特点是什么?从C语言开始讲,C语言是一种结构化语言,模块化编程,便于程序的调试,依靠非常全