dynamic初探:
以前因为某些特殊原因,需要动态的调用外部类(假设这个类是实现了某个带有参数的接口函数的),通常我们只能用反射了。示例代码如下:
Assembly asm = Assembly.LoadFile(“xxxxx”)
asm.CreateInstance("MyAssembly.ClassName").GetType().InvokeMember("Say", BindingFlags.InvokeMethod, null, asm.CreateInstance("MyAssembly.ClassName "), new string[] { "aaa" });
这里顺便简略说一下反射流程:首先通过绝对路径加载某个NET的dll文件,然后创建该assembly中某个class的instance(该class必须有无参构造函数),获取其类型之后动态调用其函数Say,“BindingFlags.InvokeMethod”表明是一个普通类方法,“null”的地方是传递一个参数名的,和指明最后的string[]中的一串values内容一一匹配的……可见使用反射调用函数是很痛苦的一件事情。
现在呢?您根本不需要那么麻烦了!因为C#的dynamic会为您做好一切的,下面就是见证奇迹的时刻——
Assembly asm = Assembly.LoadFile("xxxxx");
dynamic dfun = asm.CreateInstance("MyAssembly.ClassName");
dfun.Say("Hello!");
注意到咖啡色的代码了么——什么?dynamic竟然可以智能感知出动态加载的那个类的方法Say?其实不然:当你按下这个点的时候,IDE是没有智能感知的,但是如果你知道这个类是有这个方法(因为接口给了其一个契约,必须实现接口中的方法;而接口的方法是公开的),你就可以完全不理会智能感知,照样写,照样编译通过运行。神奇吧!
看到这里,你就不会认为dynamic和var是“差不多”的概念了(var无非是根据赋值的类型编译器自己判断;且var不能作为函数返回值类型,但是dynamic可以)。
或许有人会疑问:dynamic可以完全替代类似像简单工厂、抽象工厂一类的东西了咯?我的理解是——不对!从上面的定义中可以得知:dynamic必须首先获取对象实例,然后动态反射是它做的事情;如果完全取代反射,实例也获取不到,如何反射呢?真是“巧妇难为无米之炊”啊!
说道dynamic可以作为返回值,下面给出一个例子:
class DynamicClass
{
public int Num1 { get; set; }
public int Num2 { get; set; }
public DynamicClass(int n1, int n2)
{
Num1 = n1;
Num2 = n2;
}
public dynamic DynamicAction
{ get; set; }
}
主函数注意咖啡色部分:
static void Main(string[] args)
{
DynamicClass t = new DynamicClass(1, 2);
t.DynamicAction = new Func<int, int, double>((x, y) => x + y);
Console.WriteLine(t.DynamicAction.Invoke(t.Num1,t.Num2));
}
道理很简单:因为dynamic类型可以赋值任何东西(包括匿名委托),所以我创建了一个匿名委托给它。然后调用计算结果(匿名委托的调用使用Invoke,可以省略)。
但是……dynamic不仅仅可以动态反射类方法和属性,还可以“空中楼阁”般动态地去创建一个类方法和属性,并且赋值,相信吗?这是第二话。