C# 4.0 Dynamic关键字全解析(转)

两个问题是:


◆写程序时少了智能感知;


◆运行程序时速度变慢(反射)。

今天看完New features in CSharp
4.docx才恍然明白,趁着没事,把东西整理一下,希望能对暂时还不明白dynamic有什么用的朋友提供一些参考。当然,由于本人才疏学浅,不保证所有的观点都是正确的,希望大家用辩证的眼光来看这篇文章,如有错误之处,请大伙批评指正。

言归正传,dynamic关键字用于声明一个动态对象,然后通过该动态对象去调用方法或读写属性。

在使用C#
2.0或3.0的时候,如果一个对象需要在运行时才能确定,并且没有接口和基类方面的信息,那我们一般使用反射技术来调用这个未知对像的方法或属性,而C#
4.0提供的dynamic可以帮我们简化这些工作。假设我们的程序会在运行时取得一个不确定类型的对象,但这个对象一定会有个Print()方法,我们需要调用这个方法打印出一些信息,那么在C#
4.0下面,我们可以用下面的两句代码来实现这个需求。

这种解决方式比起用反射调用Print方法,应该简洁很多吧?程序员要做的就是别把方法名Print()打错,VS2010是不会为dynamic对象提供智能提示的,因为VS不知道运行时这个unknowObj会是什么东东……

到这里,应该有不少的朋友可以从这个例子上看出,当程序编译到unknowObj.Print()的时候,VS会帮我们生成反射的代码,用反射的方式去调用Print这个方法,实质上就是帮我们自动反射了。

如果能理解这一点,那也就不难理解C#为啥要搞dynamic这个既没智能感知,运行又慢的怪物出来了。

按New features in CSharp 4的说法,dymanic主要应用于下面的场景:

1、自动反射

2、COM组件互操作

3、混合编程,例如IronRuby和IronPython

4、处理Html DOM对象

如果有处理过上面这些工作的朋友们,应该不难理解了吧。

具体的内容,还请大伙自己看看New features in CSharp 4,里面说得比较详细。以上介绍C# 4.0的dynamic。

C#4.0的dynamic用法(一)——巧用反射
本文来自-拍搜学院:http://www.pasou.cn/edu/html/List18250.html

在平时做框架架构设计的时候,头疼之一的是处处得采用反射,但有了C#4.0,发现dynamic完全可以取代反射,这个功能让我有些激动,立马在VS2010将日志跟踪器框架里的第一个反射的代码升级到C#4.0,结果一点都不令人失望,代码简化了很多。
 
先看看用dynamic替换反射后的代码吧:
 
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Reflection;
6 using System.IO;
7 /********************************
8  * Updated by Lihua at 03/13/2009
9  *
10  * 更新功能:
11  * 1. 升级到C#4.0,加入dynamic代替反射
12  * 2. 如果Zivsoft.Log.dll不存在,日志不输出
13  * 3. 项目编译不依赖于Zivsoft.Log.dll
14  ****************************************/
15 namespace Zivsoft.Data
16 {
17     /// <summary>
18     /// 只提供持久数据层框架里的类使用
19     /// </summary>
20     internal class Logger
21     {
22         private static Assembly _assemblyFile;
23         private static dynamic _logger;
24         static Logger()
25         {
26             var strDllFile = AppDomain.CurrentDomain.BaseDirectory + "Zivsoft.Log.dll";
27             if (File.Exists(strDllFile))
28             {
29                 _assemblyFile = Assembly.LoadFile(strDllFile);
30                 try
31                 {
32                     _logger = _assemblyFile.CreateInstance("Zivsoft.Log.Logger", false, BindingFlags.CreateInstance, null, null, null, null);
33                 }
34                 catch {
35                     _logger = null;
36                 }
37             }
38         }
39
40         public static void LogInfo(string message, params object[] args)
41         {
42             if (null != _logger)
43             {
44                 _logger.LogInfo(message, args);
45             }
46         }
47
48         public static void LogWarning(string message, params object[] args)
49         {
50             if (null != _logger)
51             {
52                 _logger.LogWarning(message, args);
53             }
54         }
55
56         public static void LogError(string message, params object[] args)
57         {
58             if (null != _logger)
59             {
60                 _logger.LogError(message, args);
61             }
62         }
63
64         public static void LogDebug(string message, params object[] args)
65         {
66             if (null != _logger)
67             {
68                 _logger.LogDebug(message, args);
69             }
70         }
71
72         public static void LogError(Exception e)
73         {
74             LogError("{0}", e);
75         }
76     }
77 }
78
 
以上是持久数据层调用日志跟踪器的入口代码,以前采用反射,刚被我用dynamic改了过来,经调试一点问题都没有,所以这让我欣喜,因为接下来的我的很多框架采用反射的机制将都可能被dynamic替换,比如《持久数据层框架》中的被反射的SQLServer, MySQL, Access等等数据库。
 
不多写了,大家仔细体会吧。

dynamic 应用之简化COM互操作性
C# 4.0包含了多个特性,改进了与传统COM API接口如Office自动化等的互操作性。Dynamic类型、命名参数以及可选参数也属于改进中的一部分。
许多的COM方法允许其参数和返回值类型为object,因此对于强类型语言如C#来说,就需要做大量的强制类型转换。然而在C# 4.0中,如果在编译时加上/link选项,则dynamic类型就会起新的效果:它使得COM接口方法签名中的object类型(参数类型或返回类型)被视为dynamic,因而能够避免大量的类型转换工作。例如,下面的语句对此进行了对比。
// 没有用 dynamic.
((Excel.Range)excel.Cells[1, 1]).Value2 = "Name";
Excel.Range range = (Excel.Range)excel.Cells[1, 1];
// 用了dynamic,
excel.Cells[1, 1].Value = "Name";
Excel.Range range = excel.Cells[1, 1];
dynamic应用之混合编程(下面是利用dynamic调用IronPython的例子)

using IronPython.Hosting;
using Microsoft.Scripting.Hosting;
Console.WriteLine("Loading random.py...");
ScriptRuntime py = Python.CreateRuntime();
dynamic random = py.UseFile("random.py");
Console.WriteLine("random.py loaded!");
var items = Enumerable.Range(1, 7).ToArray();
for (int s = 0; s < 10000; s++) {
    random.shuffle(items);
    Console.Write("Sequence {0}: ", s);
    foreach (int i in items) {
        Console.Write("{0} ", i);
    }
    Console.WriteLine();
}
对于类型为dynamic的对象或者表达式,编译器的角色就是将每个表达式预期执行的动作封装起来,在运行时刻,对储存的信息进行检查,任何无效语句均会触发运行时异常。
大多数dynamic操作的结果的类型也是dynamic的。例如,如果将鼠标指针停留在下例的testSum上,智能提示会显示 (local variable) dynamic testSum。
dynamic d = 1;
var testSum = d + 3;
// 将鼠标指针停留在下面的testSum上.
System.Console.WriteLine(testSum);

posted @ 2011-06-11 14:42  董雨  阅读(347)  评论(0编辑  收藏  举报