全面讲解:委托、事件

每个编程者在项目中必定绕不开的话题:委托和事件。对于初学者来说,总会感觉有些难以理解,或者说无法自己随意运用。本文对委托、事件做一个详细的讲解,即是基础知识的自我温故,同时亦是记录。篇幅有些长,如果认真阅读,相信你会有所收获。

《Introducing Visual C# 2010》(Adam Freeman著,Apress出版)一书的第10章中有这样的介绍:

Delegates are special types thatencapsulate a method, similar to function pointers found in other programminglanguages. Delegates have a number of uses in C#, but you are most likely toencounter a special type of delegate—the event. Events make notifyinginterested parties simple and flexible, and I’ll explain the convention fortheir use later in the chapter.

委托是封装方法的特殊类型,它类似于其它编程语言中的函数指针。委托在C#中有大量运用,但你最可能遇到的是一种特殊的委托类型— 事件。事件使得对相关部件的通知变得简单而灵活,本章后面将解释其使用约定。

I’ll also explain the Func and Action typesthat let you use delegates in a more convenient form and that are usedextensively in some of the latest C# language features, such as parallelprogramming. We’ll finish up this chapter with a look at anonymous methods andlambda expressions, two C# features that let us implement delegates withouthaving to define methods in our classes.

我也会解释Func和Action类型,它们让你以更方便的形式使用委托,而且在一些最新的C#特性中也有广泛使用,如并行编程。本章最后考察匿名方法和lambda表达式,这是让我们不必在类中定义方法就可以使用委托的两个C#特性。

 

委托:

委托定义:将函数作为另一个函数的参数进行调用。另外的解释:当一个类或者是进程需要调用另外一个方法时,需要借助另外的类或者是进程进行调用,这种机制称为委托。网上有大牛说:委托可以理解为函数指针,不同的是委托是面向对象、类型安全的。

实现步骤:

1、声明一个委托类型:

public delegate int CalculateDelegate(int x, int y);

2、定义一个委托对象:

CalculateDelegate calculateDelegate = new CalculateDelegate(Add);

其中Add是委托封装的方法;

3、执行委托方法:

calculateDelegate(2, 3);

其中委托绑定的方法Add:

public static int Add(int x, int y)
{ return x + y;}

 

事件:

事件是一种特殊类型的委托

拿winform中button双击举例说明委托可能更加贴切:

声明一个委托,并声明一个事件:

public delegate void EventHandler(object sender, EventArgs e);
public event EventHandler Click;

绑定一个事件:

this.button1.Click += new System.EventHandler(this.button1_Click);

this.button1_Click是一个方法:

private void button1_Click(object sender, EventArgs e){}

 

拿一个实际项目举例说明:

匿名方法:

匿名方法(Anonymous methods) 提供了一种传递代码块作为委托参数的技术。匿名方法是没有名称只有主体的方法。在匿名方法中您不需要指定返回类型,它是从方法主体内的 return 语句推断的。

在之前讲解委托时写到绑定方法:

CalculateDelegate calculateDelegate = new CalculateDelegate(Add);
public static int Add(int x, int y)
{
return x + y;
}

如果使用匿名方法重写上面的代码:

CalculateDelegate calculateDelegate = delegate(int x, int y){return x + y;};

可见:匿名方法绑定委托直接省去了编写一个单独的方法,使得代码更为简洁。

项目中,使用委托时,很多时候编辑器会帮助我们把方法直接放入合适的委托对象中,但有时候编辑器帮助不了我们,比如:Control.Dispatcher.Invoke(delegate). 例如:

this.btnExit .Dispatcher .Invoke (new Action(() => {}));

 

Lambda表达式:

Lambda 表达式是一种匿名函数,简单地说,它是没有声明的方法,也即没有访问修饰符、返回值声明和名字;

C#的Lambda 表达式都使用 Lambda 运算符 =>,该运算符读为“goes to”。语法如下:

(object argOne, object argTwo) => {; /*Your statement goes here*/}

用Lambda表达式重写上面使用匿名方法编写的委托实例,在匿名方法的基础上,编写如下:

方式一:

CalculateDelegate calculateDelegate = (int x, int y) => { return x + y; };

方式二,更简单的表达:

CalculateDelegate calculateDelegate = (x, y) => { return x + y; };

方式三,再简单:

CalculateDelegate calculateDelegate = (x, y) => x + y;

从上面可以看出,Lambda仅仅是在匿名方法的基础上加上 => 符号,但是却让整个代码实现起来显得更为优雅。 

 

泛型委托:

在.net平台下有Microsoft自带的泛型委托,如:Action,Action<T>,Fun<T>等。实际使用中,如果需要用到泛型委托,系统内置的委托基本上就能满足需求了,下面一一介绍它们的原型及调用实例。

Action

系统封装的Action委托,没有参数没有返回值。调用实例为:

public delegate void Action();
static void Main(string[] args)       
{
  Action action = new Action(Method);
  action();
}
private static void Method()
{
  Console.WriteLine("i am is a action");
}

如果方法的表达很简单,可以使用Lambda表达式,代码如下: 

Action action = () => { Console.WriteLine("i am is a action"); };

 

Action<T>

系统封装的Action<T>委托,有参数但是没有返回值。调用实例为:

public delegate void Action<in T1, in T2>(T1 arg1, T2 arg2);
static void Main(string[] args)        
{
  Action<int,int> action = new Action<int,int>(Method);
  action(2,3);
}
private static void Method(int x,int y)
{
  Console.WriteLine("i am is a action");
}

 

使用Lambda表达式编写Action<T>代码如下:

Action<int, int> action = (x, y) => { Console.WriteLine("i am is a action"); };

 

Fun<T>

系统封装的Fun<T>委托,有返回值。调用实例为:

public delegate TResult Fun<in T1, in T2, out TResult>(T1 arg1, T2 arg2);
static void Main(string[] args) 
{
  Fun<int, int, bool> fun = new Fun<int, int, bool>(Method);
  bool ret = fun(2,3);
}
private static bool Method(int x,int y)
{

  if (x + y == 5) return true;
  else return false;
}

 

使用Lambda表达式编写Fun<T>,代码如下:

Fun<int, int, bool> fun = (x, y) =>            
{
  if (x + y == 5) return true;
  else return false;
};

 

Fun<T>没有参数有返回值的情况:

Fun<bool> fun = () =>    
{
  int x = 4;
  int y = 3;
  if (x + y == 5) return true;
  else return false;
}; //也可以如此编写Fun<bool> fun = () => false;

  

多播委托:

最后说下多播委托,所谓多播委托,即 “多路广播委托”(MulticastDelegate)。从它的名字就可以看出,此种委托可以像广播一样将影响信息“传播”到四面八方。多播委托类拥有一个方法调用列表,调用委托时,它就会逐一调用该列表中的方法,从而实现多重影响。比较简单,暂不举例说明了。

 

本文暂且告一段落,如果想查看更多文章,请关注“小项目笔记”公众号;

如有疑问:可加入QQ群号:732982683

 

posted @ 2019-12-10 08:54  小项目笔记  阅读(944)  评论(0编辑  收藏  举报

更多文章请关注公众号:小项目笔记

小项目笔记