在上一篇有关.Net 轻量 ORM Dapper 的介绍中我们提出了两个疑问,其中之一就是怎么让 Dapper 查询传参可变的问题,当然这里主要说是个数可变。这里我们就介绍C#4.0的新特性之一—— dynamic 。
C#4.0常用新特性
C#4.0引入了很多新特性方便我们进行开发,其中常用的包含以下四种。
- 可选参数
为方法的参数设定默认值,标识它是可选的,public static void Show(string str1="str1",string str2="str2") { Console.WriteLine(str1 + str2); }
- 命名参数
上面的方法可以像下面遮掩的
运行结果:str1msg。当你的方法有多个同一类型的可选参数(optional parameters)时,命名参数(Named parameters)特别有用。如果不用命名参数,编译器会把传参赋给第一个符合类型的参数,运行结果就会是:msgstr2。Show(str2:"msg");
- Dynamic 特性
dynamic关键字用于声明一个动态对象,然后通过该动态对象去调用方法或读写属性。以前我们都是在运行时通过反射,Emit,CodeDom等技术来完成。创建一个dynamic类型的对象需要使用一个特殊的构建器叫ExpandoObject。dynamic person = new System.Dynamic.ExpandoObject(); person.Name = "cary"; person.Age = 25; person.ShowDescription = new Func<string>(() => person.Name + person.Age); Console.WriteLine(person.Name+person.Age+person.ShowDescription()); Console.ReadLine();
C#4.0之Dynamic介绍
dynamicl 类型可以很方便的随意插入字段、属性、方法。dynamic的出现让C#具有了弱语言类型的特性。dynamic类型的变量,不是在编译时候确定实际类型的, 而是在运行时。所以
编译器在编译的时候不再对类型进行检查,编译期默认dynamic对象支持你想要的任何特性。也就是说诸如下面的这两行代码,在程序编译时不会报错,而是在程序运行时报错:
dynamic a = "test";
a++;
这就要求我们在使用 dynamic 关键字时要特别小心。
在上面的例子中,细心的同学会发现 dynamic 类型需要借助 System.Dynamic.ExpandoObject 来实现,ExpandoObject() 是另一个重要的C#4.0特性之一,为了探讨这一特性,我们首先来看
用dynamic增强C#泛型表达力中的一段代码:
static class Calculator {
public static T Add<T>(T t1, T t2) {
dynamic d1 = t1;
dynamic d2 = t2;
return (T)(d1 + d2);
}
}
public static void Main(string[] args){
int i = Calculator.Add(1, 2);
double d = Calculator.Add(1.1, 2.2);
string s = Calculator.Add("abc", "def");
Console.WriteLine(i + " " + d + " " + s);
}
作者在文中指出
C#代码是为了通过动态类型来实现基于duck typing的泛型参数约束。ExpandoObject 是C#支持Duck Type的根本原因。在Visual Studio 2010 中我们可以看到该类的成员列表,截图如下:
所属方法都是虚方法,我们可以重写这些虚方法。这里主要看TryInvokeMember()方法。这个方法VS2010给出了详细的描述。
简单介绍一下如何使用这个方法:假设我们一个类OurClass它继承了DynamicObject 这个Class。OurClass中有一个方法OurMethod()。接着在OurClass 类中 重写 TryInvokeMember这个基类虚方法。以上设置完后以后只要OurClass 的OurMethod方法一旦被调用都先执行一下重写后的TryInvokeMember()方法。也许您会问这样到底有何用途?OK!请先看javascript这段代码片段:
function tryInvokeMember(obj) {
if (obj && typeof obj.ourMethod === "function") {
return obj.ourMethod();
}
alert('未找到!');
return null;
}
var ourObj1 = {};
ourObj1.Method = function () {
alert('111');
};
var ourObj2 = {};
ourObj2.ourMethod = function () {
alert('已经找到ourMethod并且执行');
};
tryInvokeMember(ourObj1);
tryInvokeMember(ourObj2);
大家读完这段js代码后应该会明白为什么我要重点讨论C#4.0中的DynamicObject了吧?真正的目的就是:在DuckType 类(鸭子) 方法(鸭子叫)执行之前,我们要判断对象的类是否是具备鸭子叫的功能?如果不具备就不应该执行,否则程序势必会抛出异常。C#中如何实现呢?步骤如下:
- 建立DynamicAnimal 类继承DynamicObject类,并且重写TryInvokeMember虚方法:
<strong> </strong>public class DynamicAnimal : DynamicObject { public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) { bool success = base.TryInvokeMember(binder, args, out result); //如果方法不存在,请将result 这个out参数赋值为null if (!success) result = null; //如果这个地方返回false 将会引发异常 return true; } }
- 建立两个DuckType类,分别为Duck 和 Human:
public class Duck : DynamicAnimal { public string Quack() { return "鸭子嘛,就Quack吧!"; } } public class Human : DynamicAnimal { public string Talk() { return "人类是用Talk,而不是Quack"; } }
- 在Console 内 建立DuckType的调用方法:
public static string DoQuack(dynamic animal) { string result = animal.Quack(); return result ?? "...人类当然不会鸭叫..."; }
- Console 内 Main方法调用:
static void Main(string[] args) { var duck = new Duck(); var cow = new Human(); Console.WriteLine("鸭子是Quack"); Console.WriteLine(DoQuack(duck)); Console.WriteLine("人类是talk"); Console.WriteLine(DoQuack(cow)); Console.ReadKey(); }
程序的执行结果如下:
var、object、dynamic比较
在语法上这三者的用法很相近
var a=1;
object a=1;
dynamic c=1;
以及
var a = new string[]{"1"};
object b = new string[]{"1"};
dynamic c = new string[]{"1"};
比较一下有助于记忆。
var是C# 3中引入的,其实它仅仅只是一个语法糖. var本身并不是一种类型, 其它两者object和dynamic是类型。var声明的变量在赋值的那一刻,就已经决定了它是什么类型。所以如果你这样使用,就会有编译错误:
var a = 1;
a = "Test";
object之所以能够被赋值为任意类型的原因,其实都知道,因为所有的类型都派生自object. 所以它可以赋值为任何类型:
object a = 1;
a = "Test";
dynamic是C#引入的新类型,它的特点是申明为dynamic类型的变量,不是在编译时候确定实际类型的, 而是在运行时。所以下面的代码是能够通过编译的,但是会在运行时报错:
dynamic a = "test";
a++;
上面代码内部处理的过程是怎样的呢?首先, dynamic类型赋值为字符串"test", 运行++操作的时候,.net会去寻找当前的赋值类型string中是否支持++操作,发现不支持,出现异常。所以,如果这样修改一下,就可以让代码正常运行起来。
dynamic a = "test";
a = 1;
a++;
结语
以上的探讨是从使用角度出发对 C#4.0 新特性 dynamic 进行的介绍,若要对 dynamic 有更全面的理解,可以移步微软的msdn官方文档上查看 dynamic 更专业的介绍。
传送门:
- dynamic(C# 参考)https://msdn.microsoft.com/zh-cn/library/dd264741.aspx
- 使用类型 dynamic(C# 编程指南) https://msdn.microsoft.com/zh-cn/library/dd264736.aspx