Framework 3.5学习笔记

    前一阶段vs2008终于正式推出了,忙着学习3.5的新功能,今天就写一下学习成果吧。(当然包括c# 3.0和vb9的新特性)
    个人感觉,新语法的最终要的两个语法是:扩展方法和Lambda表达式,当然不是说其它的新特性不重要,只是个人感觉比较简单,没有什么需要花大力气去学习的。

    扩展方法应该说是一个非常甜的语法糖,为了给一些类增加功能,必须要新建一个Utility,然后给出一些静态方法,调用时,还必须Utility.静态方法(实例,...)的绕圈方式调用,扩展方法从本质上还是这样子,只不过,在高级语言里面用非常简单的方式直接调用,编译器会自动找到适合的静态方法,并且在IL级别上还原为Utility.静态方法(实例,...)的形式。换而言之,在IL级别上根本没有什么扩展方法,IL上只有一个Utility类和几个静态方法而已。
    但是,这个不大的修改,确实在一方面极大的简化了编程者的时间和精力(要记住哪个特定Utility下有哪个特定静态方法也是一件很累得事情)。另一方面,也是表现出了IL在设计方面的超前性,运行时还是2.0的运行时,而且扩展方法本质上还是用的1.0起就存在的特性(Attribute),将特性和编译器相结合,就可以看到这个令人眩目的方案。

    在看看Lambda表达式,当时的第一感觉是2.0里面的匿名方法,确实,很多地方很像。
    对比c# 3.0与vb9,可以发现有几个方面不同:
    在c# 3.0中,必须要显式的告诉编译器,某个Lambda表达式是编译成一个匿名方法还是一个表达式树,如果不指明,编译器会报错,因此,不支持匿名委托。
    在vb9中,如果没有显式的告诉编译器要编译成一个表达式树,那么编译器就自动把Lambda表达式编译成一个匿名方法,因此可以理解为支持匿名委托。
    在c# 3.0中,因为匿名方法支持多行的表达式,因此,可以写一个多行语句的,或者没有返回值的Lambda表达式。
    在vb9中,Lambda表达式被限制在一句,并且必须要有返回值。

    因为这些不同,所以,有的时候感觉某些功能在c#中很简单,而另外一些功能在vb中很简单。
    举例来说,因为vb支持匿名委托,因此可以在声明完立即调用,而c#必须分开。vb在某些特例下更接近正统的函数式变成语言。但是c#却又能提供复杂的匿名方法,而vb却不得不显式的声明一个方法来完成对应的功能。
    来看一个特例,利用Y combinators来算阶乘:
    c#版的实现,摘自Mads
public class Program
{
  
delegate T SelfApplicable<T>(SelfApplicable<T> self);

  
static void Main(string[] args)
  
{
     
// The Y combinator
     SelfApplicable<Func<Func<Func<int,int>,Func<int,int>>,Func<int,int>>
     
> Y = y => f => x => f(y(y)(f))(x);
     
// The fixed point generator
     Func<Func<Func<intint>, Func<intint>>, Func<intint>> Fix = Y(Y);
     
// The higher order function describing factorial
     Func<Func<int,int>,Func<int,int>> F = fac => x => x == 0 ? 1 : x * fac(x-1);
     
// The factorial function itself
     Func<int,int> factorial = Fix(F);
     
for (int i = 0; i < 12; i++)
     
{
       Console.WriteLine(factorial(i));
     }

  }

}
    在看一下vb的实现,载自装配中的脑袋
Dim Y = Function(f As Func(Of Func(Of ObjectObject), Func(Of ObjectObject))) _
                    (
Function(h As Func(Of Object, Func(Of ObjectObject))) Function(x) f(h(h))(x)) _
                    (
Function(h As Func(Of Object, Func(Of ObjectObject))) Function(x) f(h(h))(x))

Dim fact = Y(Function(self As Func(Of ObjectObject)) Function(n) If(n = 01, n * self(n - 1)))

Dim result = fact(4)
    可以发现vb的写法非常简单,不过因为是用弱类型的缘故,计算时间是c#版的一倍。不过可以稍微改进一下:
Shared Function Foo(Of T)(func As Func(Of Func(Of T, T), Func(Of T, T))) As Func(Of T, T) 
   
Dim Y = Function(f As Func(Of Func(Of T, T), Func(Of T, T))) _ 
           (
Function(h As Func(Of Object, Func(Of T, T))) Function(x) f(h(h))(x)) _ 
           (
Function(h As Func(Of Object, Func(Of T, T))) Function(x) f(h(h))(x)) 
   
Return Y(func) 
End Function
 

Sub Bar() 
   
Dim fact = Foo(Of Integer)(Function(self) Function(n) If(n = 01, n * self(n - 1))) 
   
Dim result = fact(4
End Sub
    通过泛型把速度可以提升到接近c#版,并且,这个方法也可以被c#中直接引用,作为类库。当然,这里的速度和直接用代码递归实现的速度相差还是比较远,因为,其中要创建多个委托对象,而在计算阶乘的例子中,创建对象的代价相对于运算而言是相当昂贵的。

    当然,vb的缺点也说过了,不支持多句语句的Lambda表达式,可以说是个比较致命的伤,相对而言,c#在这方面就比较强。

    再说一下Lambda表达式和表达式树,以前在某个项目里面,我就写过一个简单的表达式树,当然不会像3.5的表达式树那样复杂,也不存在Compile方法,所有的计算是基于解析的,当然也有转换成Sql的实现(因为表达式比较少,所以实现相对比较简单)。但是,在与语言集成方面要大大一个折扣,用Linq可以轻松的创建一个表达式树,而不用在代码中不停的new节点。当然,如果要动态的添加修改表达式树,那么,就又回到了类似以前的方式。当然,在表达式的丰富程度上应该说是比较完善的,而且支持Compile方法,将表达式树变成IL。唯一比较遗憾的是,没有Compile的时候,不能通过参数解释运行表达式树获得结果(或者有这个方法,看漏了)。。。

    以上就是最近这一个月的学习笔记,下一个月继续学习Linq。
原文地址:https://www.cnblogs.com/vwxyzh/p/1023169.html