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++好像就是这样被毁掉的.C# 3.0 Orcas 简介_c# 真怕以后出现n多版本的C#.