zoukankan      html  css  js  c++  java
  • 一起谈.NET技术,C# 委托,事件和Lambda表达式 狼人:

      关于这个论题,Delegates, Events, and Lambda Expressions 对此有比较深入的分析,可以参考。C# vs C++之一:委托 vs 函数指针 比较了委托和C++指针的区别。

      .NET 中的委托确实和C/C++的函数指针非常相似。它是一个值类型,它包装了一个指向方法的引用。它的作用也是为了能够将方法和变量一样作为参数传递。委托的典型应用是控件的事件处理方法。很显然,一个控件在设计的时候没有办法知道当特定事件发生的时候,需要什么方法来处理,这就需要将方法作为参数传递给控件。在LINQ中,也大量用到了委托。

      声明一个委托要使用delegate关键字,如下:

    delegate int Echo(string message);

      这句代码声明了一个委托类型,这个委托类型的实例可以接受参数为string,返回值为int型的函数。这个方法可以是对象的方法,也可以静态方法,还可以是匿名方法,只要方法的签名和返回值是和声明一致的。这和C的函数指针很像,但是函数指针仅仅包含函数入口地址,而委托是一个类型,它具有比函数指针更强的功能。其中一点就是当方法是实例方法的时候,这个方法可以获得对象的其他变量的值,文首的第二篇文章对此有详细介绍,不再赘述。第二点就是委托是支持多播的,也就是一串方法可以可以依次被执行。例如:

    static int EchoOriginal(string message)
    {
    Console.WriteLine(message);
    return 1;
    }

    static int EchoReverse(string message)
    {
    StringBuilder sb=new StringBuilder();
    for(int i=message.Length-1;i>=0;i--)
    sb.Append(message[i]);
    Console.WriteLine(sb.ToString());
    return -1;
    }

    static void Main(string[] args)
    {
    Echo eo = EchoOriginal;
    Echo er = EchoReverse;
    Echo all = eo + er;
    eo("Hello world");
    int i=all("Hello Delegate");
    Console.WriteLine(i);
    }

      我们定义两个方法,这两个方法都符合Echo的声明,最后Echo的all实例可以接受两个委托,调用all的时候,eo,er会被一次钓鱼,返回值是最后一个委托的返回值。程序的输出是:

      Hello world
      Hello Delegate
      etageleD olleH
      -1

      事实上,方法并不需要和委托声明类型的签名完全一致,.net允许方法的返回值是继承自声明的返回值的类型,方法的参数类型是声明的参数的父类型。这就是Covariance and Contravariance in Delegates.

      .NET的事件机制是以委托为基础的。事件机制有两部分组成,一部分是事件发布者,一部分是事件响应者。其实现原理就是由事件发布者声明一个委托对象,由事件响应者向那个委托挂载具体的处理方法,事件发布者在需要的时候调用这个委托,这样响应者的代码就会被执行。事实上,.NET也是这么做的。C#的event关键字就仅仅做了少量的工作,其中包括为类生成一个私有的delegate. event所支持的委托是有限制的委托,它的返回值必须是void,参数是两个,第一个是事件发生者,第二个参数是事件需要携带的参数。最简单的事件处理委托.net已经声明了:

     public delegate void EventHandler(
    Object sender, EventArgs e )

      声明事件的基本方式是 event 委托类型事件名称;

      举个例子,有这样的类,每当找到一个奇数,他就会触发一个事件。我们的程序在接到这个事件的时候在屏幕输出一个提示。类的代码可以这样实现:

    public class OddFinder
    {
    public event EventHandler FindOdd;

    public void Find(int from, int to)
    {
    for (int i = from; i <= to; i++)
    {
    if (i % 2 != 0)
    if (FindOdd != null)
    FindOdd(this, EventArgs.Empty);
    }
    }
    }

      这个类很简单,展示了发起事件的基本方法。首先声明一个事件,指明这个事件处理函数的委托类型。在需要触发事件的时候,首先判断是否有事件处理函数挂载,然后调用这个委托即可。外部处理程序把事件处理程序挂载上去:

    static void Main(string[] args)
    {
    OddFinder f = new OddFinder();
    f.FindOdd += new EventHandler(f_FindOdd);
    f.Find(1, 5);
    }

    static void f_FindOdd(object sender, EventArgs e)
    {
    Console.WriteLine("Found!");
    }

      这样程序运行后,就会在屏幕上输出3次Found!。如果需要在触发事件的时候,传递更多的信息给事件处理函数,比如当前找到的奇数是多少,那么就需要新建一个类继承自EventArgs,在这个类中可以添加一些需要的数据。 再声明一个委托,第二个参数为EventArgs类型即可。

      以上是基本的委托和事件的介绍,自.net 1.0开始就是如此,.net 2.0 引入了匿名方法,可以简化委托的某些操作。例如:

    f.FindOdd += delegate(object sender, EventArgs e)
    {
    Console.WriteLine("Found!");
    };

      匿名方法使用delegate关键字加上参数表,最后是代码块来定义。它可以作为委托赋值给委托类型。它可以省去单独定义一个方法的麻烦。

      .net 3.0之后引入了Lambda表达式,它进一步简化了匿名方法的写法,使得在C#中,把函数作为参数传递变得更加简单自然,从而C#变得更加具有函数式语言的味道。关于函数式语言的进一步介绍,可以参考:Functional Programming Languages 。 函数式语言的理论基础是Lambda Calulus,关于此可以参考A Tutorial Introduction to the Lambda Calculus

      Lambda表达式本质上还是匿名方法,它的一般形式是:(input parameters) => expression

      左侧是参数列表,=>右侧是方法体,可以是一个表达式(expression lambda),也可以是大括号括起来的语句段(statement lambda)。它省略了delegate关键字,使得代码更加紧凑。例如:

    n=>n%2==0;

      等价于:

    delegate(int n){ return n%2==0;}

      expression lambda 广泛应用于LINQ,它可以用来构造Expression Tree,Expression Tree是LINQ的基础。可以通过动态构造Expression Tree来实现复杂的动态LINQ查询,不过这种方法虽然通用,对于数据库查询,使用起来和传统的拼接字符串相比还是很麻烦。下文将介绍微软的一个LINQ扩展,Dynamic LINQ。

  • 相关阅读:
    linux sysfs (2)
    微软——助您启动云的力量网络虚拟盛会
    Windows Azure入门教学系列 全面更新啦!
    与Advanced Telemetry创始人兼 CTO, Tom Naylor的访谈
    Windows Azure AppFabric概述
    Windows Azure Extra Small Instances Public Beta版本发布
    DataMarket 一月内容更新
    和Steve, Wade 一起学习如何使用Windows Azure Startup Tasks
    现实世界的Windows Azure:与eCraft的 Nicklas Andersson(CTO),Peter Löfgren(项目经理)以及Jörgen Westerling(CCO)的访谈
    正确使用Windows Azure 中的VM Role
  • 原文地址:https://www.cnblogs.com/waw/p/2162663.html
Copyright © 2011-2022 走看看