C#委托和事件

其实这部分内容对于 .NET程序员而言应该是老生常谈了,但鉴于团队内常有成员对委托和事件感到混乱,因而记录下来以供分享。 
委托是C#第一个版本就引入的特性,特点如下 
1. 类似于C++中的函数指针; 
2. 允许方法像变量一样赋值; 
3. 用以作回调操作; 
4. 委托以链表的方式记录委托实例; 
5. 委托实例中使用的类型并不需要与委托声明中的类型完全吻合; 
6. 在C#2.0中引入了匿名委托,C#3.0引入了Lambda表达式作为委托实例。

通常我们据说的委托包括了委托声明和委托实例两种概念,委托声明是声明了一个委托样式,而委托实例则是与委托声明类型相符的变量,该变量记录了一系列与委托声明形式类似的方法,如

class Program
{
    public delegate void HandlerMethod();

    public static void MammalsHandler()
    {
    }

    public static void DogsHandler()
    {
    }

    static void Test()
    {
        HandlerMethod handlerMammals = MammalsHandler;
        handlerMammals += DogsHandler;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

中,public delegate Mammals HandlerMethod()是委托声明,声明HandlerMethod是一种委托类型,任何无参数且无返回值函数都可以被赋值给这种委托类型的实例,例如 
HandlerMethod handlerMammals = MammalsHandler; 
handlerMammals += DogsHandler; 
对委托实例handlerMammals赋值之后,handlerMammals委托列表中记录了两个方法,当用户invoke handlerMammals时,MammalsHandler和DogsHandler方法会依次被调用,而通过handlerMammals-=DogsHandler之类的语句可以对移除委托实例中的委托列表。

通常而言,我们使用到委托是为了实现对象的回调操作,这就要求一个对象实现的委托链表赋值可以在对象外进行操作,但该委托实例的方法列表不能在对象外部被调用, 可以看到通过上述声明和实例化的方式,需要很多代码才能进行这种可见性隔离,此时事件就派上用场了。事件的使用方法如下;

public delegate void HandlerMethod();
class EventTest
{
    public event HandlerMethod OnMammalHandled;
    public void HandleMammal()
    {
        if(null!=OnMammalHandled)
            OnMammalHandled();
    }
}
static void Test()
{
    EventTest et = new EventTest();
    et.OnMammalHandled+=MammalsHandler;
    et.OnMammalHandled+=DogsHandler;
    et.HandleMammal();
    et.OnMammalHandled-=MammalsHandler;
    et.OnMammalHandled-=DogsHandler;
}

public static void MammalsHandler()
{
}

public static void DogsHandler()
{
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

与上一个例子相关不大,但在这个例子中,事件OnMammalHandled作为一个代理,其在类实例之外只允许通过+=/-=方法进行赋值,而在类内等同于完整的委托实例,通过引入事件,可以完美地实现我们需要的回调方法效果,即对外部只具赋值可视性,对内部具有全部可视性。 
同样,事件的赋值也可以使用匿名函数或者Lambda表达式,例如

static void Test()
{
    EventTest et = new EventTest();
    et.OnMammalHandled+=delegate(){};    
    et.OnMammalHandled+=()=>{};
    et.HandleMammal();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

通过强大的委托、事件匿名函数和Lambda表达式等特性,我们可以使回调代码变得清晰简单,并且可读性更高。

猜你喜欢

转载自blog.csdn.net/aaa000830/article/details/80401177