发布日期:2009.05.11 作者:Anytao
© 2009 Anytao.com ,Anytao原创作品,转贴请注明作者和出处。
/// <summary>
/// 本文部分内容,已发表于《程序员》杂志第二期《C#,语言的变迁》
/// </summary>
引言
语言是程序开发者行走江湖的手上利器,各大门派的高手在论坛、博客为了自家门派争吵不已早是技术世界中的亮丽风景,虽多少为刚刚踏入江湖的新手提供了思考的素材,但也同时迷惑了初出茅庐的前行方向。
本文不欲计较门派的高下,旨在明辨技术的真谛,这就是.NET平台下的开发利器:C#语言,并从其变迁的进程中对于.NET技术发展把玩一番。
在下篇,我们将从历史走来,对.NET的未来做个展望性的了解,具体而言就是.NET 4.0的新东西。
.NET之,未来武器
无论如何,.NET 4.0已经在叩开新年的大门之时,以高调的姿态迎来一片掌声。广大的技术爱好者不会等待太长的时间,就能感受C#发展中的又一次变革。随着.NET 4.0在2009年的发布,我们对于C# 4.0的关注也将与日俱增。总体而言,C# 4.0的重头戏主要着眼在以下几个方面:
- 动态编程
- 并行计算
- 后期绑定
- 协变与逆变
废话少说,接下来我们一一领略C# 4.0中的语言特性。
动态编程
众所周知,C#是静态强类型语言。而在很多情况下,提供“动态”行为,是常常发生的事情,例如通过反射在运行时访问.NET类型、调用动态语言对象、访问COM对象等,都无法以静态类型来获取。因此, C# 4.0引入的又一个全新的关键字dynamic,也同时引入了改善静态类型与动态对象的交互能力,这就是动态查找(Dynamic Lookup)例如:
// Release : code06, 2009/05/07
// Author : Anytao, http://www.anytao.com
public static void Main()
{
dynamic d = GetDynamicObject();
d.MyMethod(22); // 方法调用
d.A = d.B; // 属性赋值
d[“one”] = d[“two”]; // 索引器赋值
int i = d + 100; // 运算符调用
string s = d(1,2); // 委托调用
}
就像一个object可以代表任何类型,dynamic使得类型决断在运行时进行,方法调用、属性访问、委托调用都可动态分派。同时,动态特性还体现在构建一个动态对象,在C# 4.0实现IDynamicObject接口的类型,可以完全定义动态操作的意义,通过将C#编译器作为运行时组件来完成由静态编译器延迟的操作,例如:
dynamic d = new Foo();
string s; d.MyMethod(s, 3, null);
在具体执行过程中,C#的运行时绑定器基于运行时信息,通过反射获取d的实际类型Foo,然后在Foo类型上就MyMethod方法进行方法查找和重载解析,并执行调用,这正是动态调用的背后秘密:DLR。在.NET 4.0中将引入重要的底层组件DLR(Dynamic Language Runtime,动态语言运行时),除了实现动态查找的基础支持,DLR也同时作为基础设施为类似于IronRuby、IronPython这样的动态语言提供统一的互操作机制。总而言之,动态编程将为C#在以下领域产生巨大的变革:
- Office编程与其他COM交互。
- 动态语言支持,在C#中消费IronRuby动态语言类型将并非难事,体验动态语言特性指日可待。
- 增强反射支持。
以调用IronRython为例,我们只需引入IronPython.dll, IronPython.Modules.dll, and Microsoft.Scripting.dll,即可通过创建ScriptRuntime在C#中HostingIronPython环境,进而来操作动态语言的类型信息。
ScriptRuntime py = Python.CreateRuntime();
dynamic mypy = py.UseFile("myfile.py"); Console.WriteLine(mypy.MyMethod("Hello"));
虽然从微软当前提供的技术资料和CTP演示中,动态查找还存在或多或少的问题,但是在“动态”大行其道的今天,我们无法回避也必须拥抱这个未来的主角,因为我坚信明天会更好。
并行计算
并行计算的出现,是计算机科学发展的必然结果,随着计算机硬件的迅猛发展,在多核处理器上工作已经是既存事实,而传统的编程模式必须兼容新的硬件环境才能使计算机性能达到合理的应用效果。用Anders大师的话说:未来5到10年,并行计算将成为主流编程语言不可忽视的方向,而4.0为C#打响了实现并发的第一枪。
未来的.NET Framework 4.0中将集成TPL(Task Parallel Library)和PLINQ(Parallel LINQ),这也意味着未来我们可以应用C# 4.0实现并行化应用,在统一的工作调度程序下进行硬件的并行协调,这将大大提高应用程序的性能同时降低现存并发模型的复杂性。
那么,我们应该一睹为快应用C#武器来开发并发环境下的超酷感受,在System.Threading.Parallel 静态类提供了三个重要的方法For、Foreach、Invoke可以为我们小试牛刀:
//应用TPL,执行并行循环任务
Parallel.For(0, 10, i =>
{
DoSomething(i);
});
在线程争用执行情况下,相同的操作在双核平台下运行,以StopWatch进行精确时间测试,并行环境下的执行时间为 2001ms,而非并行环境下的执行时间为4500ms,并行运算的魅力果然名不虚传。我们再接再厉应用PLINQ执行对于并行运算的查询、排序等,当前PLINQ支持两种方式ParallelEnumerable类和ParallelQuery类,例如:
int[] data = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int[] selected = (from x in data.AsParallel()
select x + 1).ToArray();
更详细的对比示例留待读者在实践中对此进行讨论,并行计算为托管代码在多核环境下的性能优化提供了统一的解决方案,而未来我们会做的更好。
备注:实际上,我们可以选择下载安装Microsoft Parallel Extensions to the .NET Framework 3.5June 2008 CTP包,就可以在.NET 3.5环境下体验并行计算的无穷魅力。
协变和逆变
协变和逆变,是为解决问题而生的。而要理清解决什么样的问题,需要首先从理清几个简单的概念开始。首先我们进行一点操作:
Derived d = new Derived();
Base b = d;
Derived类型继承自Based类型,由Derived引用可以安全的转换为Based引用,而这种转换能力可以无缝的实现在Derived数组和Base数组,例如:
Derived[] ds = new Derived[5];
Base[] bs = ds;
而这种原始转换(由子类转换为父类)方向相同的可变性,被称为协变(covariant);其反向操作则被称为逆变(contravariant)。当同样的情形应用于泛型时,例如:
List<Derived> ds = new List<Derived>();
List<Base> bs = ds;
类似的操作却是行不通的。所以,这就成为C# 4.0中完善的问题——泛型的协变与逆变:
// Release : code07, 2009/05/07
// Author : Anytao, http://www.anytao.com
List<Base> bs = new List<Base>();
List<Derived> ds = new List<Derived>(); bs = ds; //List<T>支持对T协变
ds = bs; //List<T>支持对T逆变
而在C# 4.0中,伴随着协变与逆变特性的加入,C#引入两个in和out关键字来解决问题。
// Release : code08, 2009/05/07
// Author : Anytao, http://www.anytao.com
public interface ICovariant<out T>
{
T MyAction();
} public interface IContravariant<in T>
{
void MyAction(T arg);
}
其中,out表示仅能作为返回值的类型参数,而in表示仅能作为参数的类型参数,不过一个接口可以既有out又有in,因此既可以支持协变、支持逆变,也可以同时支持,例如:
public interface IBoth<out U, in V>
{
}
命名参数和可选参数
命名参数和可选参数是两个比较简单的特性,对于熟悉其他编程语言的开发者来说可选参数并不陌生,为参数提供默认值时就是可选参数:
// Release : code09, 2009/05/07
// Author : Anytao, http://www.anytao.com
public void MyMethod(int x, int y = 10, int z = 100)
{
}
因此,我们可以通过调用MyMethod(1)、MyMethod(1, 2)方式来调用MyMethod方法。而命名参数解决的是传递实参时,避免因为省去默认参数造成的重载问题,例如省去第二个参数y调用时,即可通过声明参数名称的方式来传递:
MyMethod(20, z: 200);
相当于调用MyMethod(20, 10, 200),非常类似于Attribute的调用方式。虽然只是小技巧,但也同时改善了方法重载的灵活性和适配性,体现了C#语言日趋完美的发展轨迹。
当然,除此之外.NET 4.0还增加了很多值得期待的平台特性,也将为C#编码带来前所未有的新体验。
.NET之,趋势不可逆转
预测未来,在技术世界是常有的事儿。从高级语言的发展历史来看,编程世界从来就没有停止过脚步,变革时时发生、创新处处存在。以技术人员的角度来观摩未来,带着C# 4.0的脚步来看展望, 除了在函数式编程、并行计算和动态特性上大展拳脚,Meta Programming的概念已然浮出水面,将编译器变成一个Service,你可以自由控制在编译器和运行期的逻辑,那是多么美好而向往的未来呀,所以,我们坚信 4.0之后还有广阔的天地随着语言的变迁变得更加开阔。
概括Anders大师在C#设计过程中的思想,C#是语言美学的集大成者。例如,当使用foreach进行循环遍历之后,当应用using语句代替try/finally实现强制资源管理,当应该attribute进行运行时反射,当以LINQ进行语言级别的信息查询,这些语言级别的支持为C#实现面向对象编程带来强大的功能动力和美学感受。
注:本文代码在VS2010 CTP基础上开发,未检测任何版本更新所带来的不同,望明察。
参考文献
(Web)http://www.tiobe.com/index.php/content/paperinfo/tpci/index.html
(Web)http://weblogs.asp.net/podwysocki/archive/2008/05/24/what-is-the-future-of-c-anyways.aspx
(Web)New features in C# 4.0
(Web)http://msdn.microsoft.com/en-us/magazine/cc163340.aspx
作者简介:
王涛,网名Anytao,微软C# MVP,高级软件工程师,机械工程硕士,《你必须知道的.NET》一书作者,主要研究方向为.NET底层架构和企业级系统应用。现就职于某软件公司负责架构设计、软件开发和项目管理方面的工作。作者对.NET基础架构和CLR底层运行机制有浓厚的研究兴趣和造诣,熟悉ASP.NET、XML、WCF、SQL Server相关技术,对面向对象、设计模式和软件架构有一定的研究与实践经验。他的联系方式如下:http://www.cnblogs.com/Anytao