Implicitly typed local variables
15 var i = 5;
16 var s = "Hello";
17 var d = 1.0;
18 var numbers = new int[] {1, 2, 3};
19 var orders = new Dictionary<int,Order>();
局部变量的声明变得非常方便, 编译器会根据上下文自动推导出变量的类型.这个功能在3.0中被广泛使用.
下面的代码更加方便:
15 var sum = 0;
16 var intArray = new [] { 1,2,3,4}; //used to be new int[](1,2,3,4)
17 foreach ( var i in intArray )
18 {
19 sum += i;
20 }
在匿名类型的支持下,你甚至可以这样玩.
15 var contacts = new[]
16 {
17 new {
18 Name = "idior",
19 Website= new[] { "idior.cnblogs.com", "www.alphatom.com" }
20 },
21
22 new {
23 Name = "dudu",
24 PhoneNumbers = new[] { "www.aopdotnet.com" }
25 }
26 };
可见3.0下的代码是多么的简洁.
需要注意的是这里的var和javascript中可不一样. 它是强类型的, 也就是说var sum=0;其中的sum的类型仍然是int.
只不过这个推导过程由编译器做了, 如果你查看反编译的源代码你会发现var sum=0; 变成了int sum=0;
之所以要引入var, 更多的由于Linq中查询结果的需要. 因为对于复杂的查询语句, 你很难判断出返回的结果类型,甚至有时返回的是匿名类型,这个时候var就会大大减轻程序员的负担.
Extension methods
在2.0的集合一文中, 我对新List<T>加入的Foreach方法大加赞扬了一番, 同时也指出其不足, 并提供了一个扩展方法. 现在有了Extension Method的支持,要想对原有类扩展扩展功能简直太方便了.
比如我想为所有的集合类加入Foreach的方法.
24 class Static Algorithm
25 {
26 public static void ForEach<T>(this IEnumerable<T> collection, Action<T> action)
27 {
28 foreach (T obj in collection)
29 {
30 action(obj);
31 }
32 }
33
34 public static void ForSpecification<T>(this IEnumerable<T> collection, Action<T> action, Predicate<T> filter)
35 {
36 foreach (T obj in collection)
37 {
38 if (filter(obj))
39 action(obj);
40 }
41 }
42 }
来看看如何使用:
15 var numbers = new [] {"hello", "world", "Linq"};
16
17 numbers.ForEach (delegate(string str) // equal to Algorithm.ForEach(numbers,...)
18 {
19 Console.WriteLine(str);
20 }
21 );
Extension methods名副其实, 确实为功能扩展带来了极大的方便.
如果你接触过AOP的话,你会发现它和AOP中的静态横切(Mixin)的作用很象. Extension methods是否真的将扩展的方法加入原来的类型当中, 就像多继承那样? 答案是否定的, 这里仅仅是一个语法糖,编译器会自动将numbers.ForEach(...) 变回到Algorithm.ForEach(numbers,...).
Lambda Expressions
如果说你现在还没有习惯使用匿名方法, 没关系,一年后你也会不自觉的使用到它, 而Lambda Expressions则是对匿名方法的进一步增强, 两年后你就会使用它来代替匿名方法.
如果你看了我在CollectionClosureMethod in .Net 一文中利用匿名方法对Martin Fowler的CollectionClosureMethod in Ruby的模拟, 但是觉得很丑陋的话, 那么请你看看下面的代码:
15 managers = employees.select {|e| e.manager?} //ruby
16
17 List<Employee> managers = employees.FindAll(delegate(Employee e)
18 {
19 return e.IsManager == true;
20 }); //C# 2.0
21
22 var managers = employees.Select(e => e.IsManager==true); //C# 3.0
21 offices = employees.collect {|e| e.office} //ruby
22
23 List<Office> offices = employees.ConvertAll<Office>(delegate(Employee e)
24 {
25 return e.Office;
26 }); //C# 2.0
27
28 var offices = employees.Select(e => e.Office); //C# 3.0
有关Lambda表达式的更多内容请见这里.
Object and Collection initializers
对象的初始化的代码将变得异常简洁.
15 var idior = new Person{Name = "ning", Surname = "xu"};
16
17 var persons = new List<Person>
18 {
19 new Person{Name = "ning", Surname = "xu"},
20 new Person{Name = "Foo", Surname = "Bar"}
21 }
Anonymous types
15 var idior = new
16 {
17
18 Console.WriteLine(idior.WebSite);
19 }
Query Expressions
将关系型查询语句引入面向对象的世界, 大大增强了语法安全性, 很久以前我也对此有过介绍.
15 from c in customers
16 where c.City == "London"
17 select c
相应的Lambda表达式描述
15 customers.Where(c => c.City == "London")
该语法的表达能力非常强, 对where , select , group , orderby , into 的语法都有支持.
结合前面的Anonymous types. 还可以方便的获得多个查询结果,并包装成类
15 var payingCustomers = from c in db.Customers
16 where c.Orders.Count > 0
17 select new { Email = c.Email, Name = c.Name };
18 foreach (var c in payingCustomers)
19 {
20 SendDiscountOffer(c.Email, c.Name);
21 }
这个功能将彻底改变持久层的操作.
以上仅仅是对Linq 的初步认识, 变化之大远远超出2.0较之于1.0. 看了之后实在心痒痒的, Linq在动态语言和Function Programming方面的能力大大增强. 再对比一下java那边, 似乎还没听到6.0的什么消息, 不知道他们将如何应对.net的下一波冲击!
以上的介绍将各个新增功能分开逐一介绍, 表面看了好像仅仅是增强了一些新的语法, 增加了C#语言的灵活性, 甚至会有人认为此举得不偿失, 但是最重要的概念不是在于这些小的语言点,而是通过它们的合作而产生的LINQ. 将类似关系型(实际还是面向对象的)的语言引入到C#中,大大增强了C#对于数据的操作能力(内存数据---集合, 外部数据--DataBase,XML ).
Linq何时才能用? 虽然在语法层面Linq加入了很多新的内容, 但是在做完上面的范例之后, 你会发现Linq中并没有在CLR底层加入什么新的元素. 所有新的功能仍然是建立在泛型的基础上,然后由编译器完成大部分的代码转化和生成. 以上的程序集在reflector中都是可以被反编译的,并没有什么新的底层元素不可被识别. 因此,个人估计只要MS不断推出Linq新的测试版本, 我想Linq并不需要等到Orcas才能发布.或许在.Net 2.1时就可以正式发布了. Orcas应该不止是Linq这么简单, 它应该会在底层加入新的元素, 这样才叫主版本的变化嘛,就像2.0加入了泛型.
推而广之, 如果你想为.Net增强新的功能,比如加入AOP的功能, 那么你也可以考虑实现自己的一套增强型编译器. 不过C++好像就是这样被毁掉的. 真怕以后出现n多版本的C#.