本文探索了C# 4.0中新的动态类型、命名参数和可选参数,文中的C# 4.0动态类型实例全部在Visual Studio 2010 Beta版本中进行。Dynamic关键字可以算是C# 4.0中新增的最重要的特性了。
【51CTO译文精选】C# 4.0包括大量的增强和新增特性,包括:
1、支持动态查找
2、同时支持命名参数和可选参数
3、增强的COM互操作特性
4、支持方差
本文将只对前面两项做一些介绍,并提供一些实例,让你充分了解如果在你的应用程序中利用这些特性将会得到什么好处,后面两项将在未来的文章的进行阐述。
有些C#新特性被合并到微软新的动态语言运行库(DLR)环境中去了,动态语言运行库是.Net框架中的新特性,它可以和静态语言进行互操作。
理解DLR
DLR是构建在通用语言运行库(CLR)基础之上的,动态类型语言如Python,Ruby和JavaScript可以和大家熟悉的静态.Net语言C#,托管C++,以及VB共存,CLR为静态语言(如C#和VB)入驻和互操作提供通用平台,而DLR位于CLR之上,为动态语言入驻和互操作提供通 用平台。
DLR增加了一套服务,使得在.Net托管平台上实施动态语言更加容易,这些服务包括支持动态类型系统,标准的主机托管模式,以及快速生成动态代码。此外,DLR还让动态语言和静态语言之间实现了双向互操作。
为了支持DLR,.Net框架4.0中特地增加了一个System.Dynamic命名空间,动态语言运行库包括三层,如图1所示:
图- 1 DLR的组件:DLR包括.Net语言集成层,一套运行库代码组件和语言联编程序
1、.Net语言集成层
2、动态语言运行库代码组件
3、语言联编程序
DLR提供的服务包括:
1、动态方法调度
2、动态代码生成
3、托管API
DLR就简要介绍这些了,继续前进看看C#的新特性。
动态查找
引入动态类型后,从方法或表达式返回值时,你就再也不用担心对象的类型了,运行库根据返回值的类型执行必要的联编。
静态和动态类型
静态语言如C#,C++,Java都是在编译时执行类型检查,与此相反,动态语言如JavaScript,Perl和Ruby都是在运行时执行类型检查。C#最初被设计为基于强壮类型的语言,因为编译器可以确保类型匹配,在开发周期的早期阶段就会发现bug。现在情况发生了变化,在C#中引入了动态 类型,你可以无缝地调用不同类型的对象了,如COM和JavaScript。
Var和dynamic关键字
为了支持动态变量声明,C#4.0引入了关键字dynamic,在C#中var和dynamic关键字提供了本地类型含义,你不需要在赋值运算符左边指定数据类型,系统会动态绑定正 确的类型。但与dynamic关键字不同的是,使用var时,你必须在赋值运算符的右边指定类型。使用dynamic关键字时,你不用指定任何类型,所有 类型绑定都在运行时完成。
动态类型示例
光听似乎理解起来有点难度,我们还是来看看实际的例子吧,仔细研究以下三个业务逻辑类,以及每个类中包含的方法:
1.
2. class ProductBL
3. {
4.
public void ProcessNewProductData()
5. {
6.
Console.WriteLine("Process method of the ProductBL " +
7.
"class has been called.");
8. }
9. }
10.
class OrderBL
11. {
12.
public void ProcessNewOrderData()
13. {
14.
Console.WriteLine("Process method of the OrderBL " +
15.
"class has been called.");
16. }
17. }
18.
class CustomerBL
19. {
20.
public void ProcessNewCustomerData()
21. {
22.
Console.WriteLine("Process method of the CustomerBL " +
23.
"class has been called.");
24. }
25. }
26.
正如你所看到的,每个类都有不同的方法,假设在运行过程中,你需要调用process方法,这类问题使用动态类型就很好解决,首先,创建一个包含一系列业务逻辑实例类型的enum。
1.
2. public enum BusinessLogicObjectType {
3. ProductBL, CustomerBL, OrderBL };
4.
下面的方法返回业务逻辑类的一个实例:
1.
2. public static object GetBusinesLogicInstance(
3. BusinessLogicObjectType businessLogicObjectType)
4. {
5.
switch (businessLogicObjectType)
6. {
7.
case BusinessLogicObjectType.ProductBL:
8.
return new ProductBL();
9.
case BusinessLogicObjectType.CustomerBL:
10.
return new CustomerBL();
11.
default: return null;
12. }
13. }
14.
现在你就可以使用dynamic关键字,在运行过程中调用合适的业务逻辑实例,如下所示:
1.
2. static void Main(string[] args)
3. {
4. dynamic dynamicBLObject = GetBusinesLogicInstance(
5. BusinessLogicObjectType.ProductBL);
6. dynamicBLObject.ProcessNewProductData();
7. Console.Read();
8. }
9.
就这么简单。
如图2所示,执行这个应用程序时会显示一条消息“ProductBL类的process方法已经被调用”,在清单1中你可以看到完整的示例代码。
图- 2 示例输出:这是动态调用业务对象类方法的输出
清单1 Dynamic关键字
1.
2. using System;
3.
4.
namespace NewCSharpFeatures
5. {
6.
public enum BusinessLogicObjectType { ProductBL, CustomerBL, OrderBL };
7.
8.
class ProductBL
9. {
10.
public void ProcessNewProductData()
11. {
12.
Console.WriteLine("Process method of the ProductBL " +
13.
"class has been called.");
14. }
15. }
16.
17.
class OrderBL
18. {
19.
public void ProcessNewOrderData()
20. {
21.
Console.WriteLine("Process method of the OrderBL " +
22.
"class has been called.");
23. }
24. }
25.
26.
class CustomerBL
27. {
28.
public void ProcessNewCustomerData()
29. {
30.
Console.WriteLine("Process method of the CustomerBL " +
31.
"class has been called.");
32. }
33. }
34.
35.
class Program
36. {
37.
public static object GetBusinesLogicInstance(
38. BusinessLogicObjectType businessLogicObjectType)
39. {
40.
switch (businessLogicObjectType)
41. {
42.
case BusinessLogicObjectType.ProductBL: return new ProductBL();
43.
case BusinessLogicObjectType.CustomerBL: return new CustomerBL();
44.
default: return null;
45. }
46. }
47.
48.
static void Main(string[] args)
49. {
50. dynamic dynamicBLObject = GetBusinesLogicInstance(
51. BusinessLogicObjectType.ProductBL);
52. dynamicBLObject.ProcessNewProductData();
53. Console.Read();
54. }
55. }
56. }
57.
命名参数和可选参数
可选参数,默认值和命名参数是更有趣的新增特性,可选参数让你可以避免在调用方法时必须传递参数,默认值让你在调用方法不用传输参数时指定其默认值,命名参数让你可以使用参数名字作为参数,而不用提供它们在参数列表中的位置,意思是你可以不按顺序向方法提供参数。还是来看看实际的例子吧。
看看下面这个方法:
1.
2. static int Add(int x = 0, int y = 0)
3. {
4.
return (x + y);
5. }
6.
正如你所看到的,参数x和y都有了默认值,add()方法使用它的参数列表进行了默认的初始化,现在你可以不用传递任何参数调用add()方法,如:
1. int result = Add();
上面这行代码会返回0,因为这两个参数都使用了其默认值0,当然,你也可以明确地传递参数给这个方法,如:
1. int result = Add(5, 6); // 返回11
可选参数应该显示在方法参数列表的末尾,换句话说就是,可选参数应该最后出现,应该先指定前面的所有需要的参数,因此,下面的方法是无效的:
1.
2. static int Add(int x = 0, int y)
3. {
4.
return (x + y);
5. }
6.
如果你编译这段代码,将会遇到错误“可选参数必须出现在所有需要的参数的后面”。
现在你也可以使用命名参数传递值了,这样就不用记住参数的顺序了,如:
1. int result = Add( y:6, x:5); //返回11
注意前面这行代码是先指定的y,后指定的x,这与add()方法中的参数定义顺序是相反的。
小结
C# 4.0中新增的最重要的特性是dynamic关键字,它让你在编译时创建对象类型,即使你不知道对象类型是什么也行。