建议15: 使用dynamic来简化反射实现

转载 2016年08月31日 10:51:03

建议15: 使用dynamic来简化反射实现

dynamic是Framework 4.0的新特性。dynamic的出现让C#具有了弱语言类型的特性。编译器在编译的时候不再对类型进行检查,编译器默认dynamic对象支持开发者想要的任何特性。比如,即使你对GetDynamicObject方法返回的对象一无所知,也可以像如下这样进行代码的调用,编译器不会报错:

  1. dynamic dynamicObject = GetDynamicObject();  
  2. Console.WriteLine(dynamicObject.Name);  
  3. Console.WriteLine(dynamicObject.SampleMethod()); 

当然,如果运行时dynamicObject不包含指定的这些特性(如上文中带返回值的方法SampleMethod),运行时程序会抛出一个RuntimeBinderException异常:

“System.Dynamic.ExpandoObject”未包含“SampleMethod”的定义。

注意 有人会将var这个关键字与dynamic进行比较。实际上,var和dynamic完全是两个概念,根本不应该放在一起比较。var实际上是编译期抛给我们的“语法糖”,一旦被编译,编译期会自动匹配var 变量的实际类型,并用实际类型来替换该变量的声明,这看上去就好像我们在编码的时候是用实际类型进行声明的。而dynamic被编译后,实际是一个object类型,只不过编译器会对dynamic类型进行特殊处理,让它在编译期间不进行任何的类型检查,而是将类型检查放到了运行期。

这从Visual Studio的编辑器窗口就能看出来。以var声明的变量支持“智能感知”,因为Visual Studio能推断出var类型的实际类型;而以dynamic声明的变量却不支持“智能感知”,因为编译器对其运行期的类型一无所知。对dynamic变量使用“智能感知”,会提示“此操作将在运行时解析”。

利用dynamic的这个特性,可以简化C#中的反射语法。在dynamic出现之前,假设存在类,代码如下所示:

  1. public class DynamicSample  
  2. {  
  3.     public string Name { get; set; }  
  4.  
  5.     public int Add(int a, int b)  
  6.     {  
  7.         return a + b;  
  8.     }  

我们这样使用反射,调用方代码如下所示:

  1. DynamicSample dynamicSample = new DynamicSample();  
  2. var addMethod = typeof(DynamicSample).GetMethod("Add");  
  3. int re = (int)addMethod.Invoke(dynamicSample, new object[] { 1, 2 }); 

在使用dynamic后,代码看上去更简洁了,并且在可控的范围内减少了一次拆箱的机会,代码如下所示:
  1. dynamic dynamicSample2 = new DynamicSample();  
  2. int re2 = dynamicSample2.Add(1, 2); 

我们可能会对这样的简化不以为然,毕竟代码看起来并没有减少多少,但是,如果考虑到效率兼优美两个特性,那么dynamic的优势就显现出来了。如果对上面的代码执行1000000次,如下所示:
  1. int times = 1000000;  
  2. DynamicSample reflectSample = new DynamicSample();  
  3. var addMethod = typeof(DynamicSample).GetMethod("Add");  
  4. Stopwatch watch1 = Stopwatch.StartNew();  
  5. for (var i = 0; i < times; i++)  
  6. {  
  7.     addMethod.Invoke(reflectSample, new object[] { 1, 2 });  
  8. }  
  9. Console.WriteLine(string.Format("反射耗时:{0} 毫秒",  
  10.     watch1.ElapsedMilliseconds));  
  11. dynamic dynamicSample = new DynamicSample();  
  12. Stopwatch watch2 = Stopwatch.StartNew();  
  13. for (int i = 0; i < times; i++)  
  14. {  
  15.     dynamicSample.Add(1, 2);  
  16. }  
  17. Console.WriteLine(string.Format("dynamic耗时:{0} 毫秒",  
  18.     watch2.ElapsedMilliseconds)); 

输出为:
  1. 反射耗时:2575 毫秒  
  2. dynamic耗时:76 毫秒 

可以看到,没有优化的反射实现,上面这个循环上的执行效率大大低于dynamic实现的效果。如果对反射实现进行优化,代码如下所示:
  1. DynamicSample reflectSampleBetter = new DynamicSample();  
  2. var addMethod2 = typeof(DynamicSample).GetMethod("Add");  
  3. var delg = (Func<DynamicSample, int, int, int>)Delegate.CreateDelegate(typeof(  
  4.     Func<DynamicSample, int, int, int>), addMethod2);  
  5. Stopwatch watch3 = Stopwatch.StartNew();  
  6. for (var i = 0; i < times; i++)  
  7. {  
  8.     delg(reflectSampleBetter, 1, 2);  
  9. }  
  10. Console.WriteLine(string.Format("优化的反射耗时:{0} 毫秒",  
  11.     watch3.ElapsedMilliseconds)); 

输出为:
  1. 优化的反射耗时:12 毫秒 

可以看到,优化后的反射实现,其效率和dynamic在一个数量级上。可是它带来了效率,却牺牲了代码的整洁度,这种实现在我看来是得不偿失的。所以,现在有了dynamic类型,建议大家:

始终使用dynamic来简化反射实现。

转自:《编写高质量代码改善C#程序的157个建议》陆敏技

相关文章推荐

改善C++ 程序的150个建议学习之建议15:尽量不要使用可变参数

建议15:尽量不要使用可变参数 在某些情况下我们希望函数参数的个数可以根据实际需要来确定,所以C语言中就提供了一种长度不确定的参数,形如:“...”,C++语言也继承了这一语言特性。在采用ANSI标准...

c\c++复习基础要点15----c++运行时类型识别 dynamic_cast typeid type_info

C++提供了两个操作符合一个类来实现运行时类型识别机制,它们是操作符dynamic_cast、操作符typeid和类type_info   dynamic_cast操作符:   dynamic...

改善C#程序的建议2:C#中dynamic的正确用法

dynamic是FrameWork4.0的新特性。dynamic的出现让C#具有了弱语言类型的特性。编译器在编译的时候不再对类型进行检查,编译期默认dynamic对象支持你想要的任何特性。比如,即使你...

并发编程的 15 条建议

  • 2011-08-30 16:53
  • 17KB
  • 下载

如何训练深度神经网络?老司机的 15 点建议

本文为印度深度学习专家、创业者 Rishabh Shukla 在 GitHub 上发表的长博文,总结了他过去的开发经验,旨在给新入门的开发者提供指导。雷锋网(公众号:雷锋网)做了不改变原意的编译。在深...

并发编程的 15 条建议(译)

并发编程的 15 条建议(译) 2010年11月04日 星期四 上午 12:05 内核专家 Bryan Cantrill 和 Jeff Bonwick 在 2008 年 9 月...

如何训练深度神经网络?老司机的 15 点建议

http://www.leiphone.com/news/201701/gOwAU7YFQkJcFkVB.html 1. 训练数据 许多 ML 开发者习惯把原始训练数据直接扔给 DNN...

并发编程的 15 条建议(译)

转自 http://blog.csdn.net/solstice/article/details/5915355 内核专家 Bryan Cantrill 和 Jeff Bonwick 在 2...

建议81:使用Parallel简化同步状态下Task的使用

建议81:使用Parallel简化同步状态下Task的使用 在命名空间System.Threading.Tasks中,有一个静态类Parallel简化了在同步状态下的Task的操作。Parallel...
  • houwc
  • houwc
  • 2016-09-08 11:28
  • 187
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)