改善C#程序的157个建议(连载15)

发表于:2011-11-04 10:10

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:陆敏技    来源:51Testing软件测试网采编

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

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

  • dynamic dynamicObject = GetDynamicObject();  
  • Console.WriteLine(dynamicObject.Name);  
  • 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出现之前,假设存在类,代码如下所示:

  • public class DynamicSample  
  • {  
  •     public string Name { get; set; }  
  •     public int Add(int a, int b)  
  •     {  
  •         return a + b;  
  •     }  
  • }
  •   我们这样使用反射,调用方代码如下所示:

  • DynamicSample dynamicSample = new DynamicSample();  
  • var addMethod = typeof(DynamicSample).GetMethod("Add");  
  • int re = (int)addMethod.Invoke(dynamicSample, new object[] { 1, 2 });
  •   在使用dynamic后,代码看上去更简洁了,并且在可控的范围内减少了一次拆箱的机会,代码如下所示:

  • dynamic dynamicSample2 = new DynamicSample();  
  • int re2 = dynamicSample2.Add(1, 2);
  •   我们可能会对这样的简化不以为然,毕竟代码看起来并没有减少多少,但是,如果考虑到效率兼优美两个特性,那么dynamic的优势就显现出来了。如果对上面的代码执行1000000次,如下所示:

  • int times = 1000000;  
  • DynamicSample reflectSample = new DynamicSample();  
  • var addMethod = typeof(DynamicSample).GetMethod("Add");  
  • Stopwatch watch1 = Stopwatch.StartNew();  
  • for (var i = 0; i < times; i++)  
  • {  
  •     addMethod.Invoke(reflectSample, new object[] { 1, 2 });  
  • }  
  • Console.WriteLine(string.Format("反射耗时:{0} 毫秒",  
  •     watch1.ElapsedMilliseconds));  
  • dynamic dynamicSample = new DynamicSample();  
  • Stopwatch watch2 = Stopwatch.StartNew();  
  • for (int i = 0; i < times; i++)  
  • {  
  •     dynamicSample.Add(1, 2);  
  • }  
  • Console.WriteLine(string.Format("dynamic耗时:{0} 毫秒",  
  •     watch2.ElapsedMilliseconds));
  • 21/212>
    《2023软件测试行业现状调查报告》独家发布~

    关注51Testing

    联系我们

    快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

    法律顾问:上海兰迪律师事务所 项棋律师
    版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
    投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

    沪ICP备05003035号

    沪公网安备 31010102002173号