Skip to main content
黑话筒

委托和事件浅解

一、委托

委托实际上就是C++里面的函数指针,你可以让这个指针指向委托定义时所声名的那种类型的函数。举个例子:

public delegate void 连接数据库委托();

表示:声名一个委托类型,这个委托叫“连接数据库委托”,它所能指向的函数都是返回值为void型,没有参数的函数。比如:

private void 连接Oracle数据库();

private void 连接SqlServer数据库();

我们现在的程序里面要根据用户设定的数据库类型,自动连接数据库。

程序里面可以这么写:

连接数据库委托 委托实例 = null;

switch(目标数据库类型)
{
    case 数据库类型.Oracle数据库:
        委托实例 += new 连接数据库委托(连接Oracle数据库);
        break;
    case 数据库类型.SqlServer数据库:
        委托实例 += new 连接数据库委托(连接SqlServer数据库);
        break;
}

委托实例(); //运行委托所指向的函数

这里就能根据上面的switch来执行相应的连接数据库函数了。

委托是种类型,所以跟其他类型一样,可以当参数传递。

委托还有一个重要特性就是多播(Multicasting)

就是说执行一个委托实例的时候,可以同时执行一个以上的函数。

比如说我的程序要连接Oracle数据库,同时还要连接SqlServer数据库,可以这么写:

委托实例 += new 连接数据库委托(连接Oracle数据库);

委托实例 += new 连接数据库委托(连接SqlServer数据库);

委托实例(); //运行委托所指向的函数

这样就同时执行了两个函数

二、委托例子的完整代码

//DelegateTest.cs
using System;
using System.Threading;

namespace ConsoleApp_CS
{
    public class AppClass
    {
        public delegate void 连接数据库委托();

        private static void 连接Oracle数据库()
        {
            Console.WriteLine("已经连接到Oracle数据库\n");
        }

        private static void 连接SqlServer数据库()
        {
            Console.WriteLine("已经连接到连接SqlServer数据库数据库\n");
        }

        public static void Main()
        {
            连接数据库委托 数据库连接;

            数据库连接 = new 连接数据库委托(连接Oracle数据库);

            Console.WriteLine("<<仅连接到Oracle数据库");
            数据库连接();    //仅连接到Oracle数据库

            数据库连接 = new 连接数据库委托(连接SqlServer数据库);

            Console.WriteLine("<<仅连接到SqlServer数据库");
            数据库连接();    //仅连接到SqlServer数据库

            数据库连接 = null;

            数据库连接 += new 连接数据库委托(连接Oracle数据库);
            数据库连接 += new 连接数据库委托(连接SqlServer数据库);

            Console.WriteLine("<<同时连接到两个数据库");
            数据库连接();

            Console.Read();
        }
    }
}

三、事件

可以这么理解:当某件事发生的时候,会有一个广播信号,告诉大家什么事情发生了。某些人可能不关心股票事件,有些人不关心其他国家发洪水事件。这样事件就需要订阅,你只订阅你感兴趣的事件。当事件发生时,那些订阅该事件的订阅者就会收到一个信号,告诉你这个事件发生了。你可以对这个事件不闻不问,这个跟没订阅该事件一样,有些人会对这个事件进行一些处理,比如:

公司饮水机在我旁边,我关心饮水机是否没水了,所以我订阅一个“饮水机没水了”这个事件。

公司饮水机.饮水机没水了 += new 公司饮水机.饮水机没水了委托(我.换水);

这样,当饮水机没水了事件触发时,我就被通知要换水,执行的是“我”这个实例的“换水”方法。

饮水机Class 看起来大概是这样的:

public class 饮水机
{
    private int 水量 = 10;
    public delegate void 饮水机没水了委托();
    public event 饮水机没水了委托 饮水机没水了;

    public void 出水(int 出水量)
    {
        Console.WriteLine("有人接水……");
        水量 -= 出水量;
        Console.WriteLine("桶里还剩{0}升水", 水量);
        if(水量 == )
        {
            当饮水机没水了();
        }
    }

    public void 当饮水机没水了()
    {
        if(饮水机没水了 != null)
        {
             Console.WriteLine("饮水机没水了,快来换水……");
             饮水机没水了();    //触发这个事件
         }
    }
}

而公司员工Class 看起来大概是这样的:

public class 公司员工
{
    public void 换水()
    {
        Console.WriteLine("我去换水,真累啊……");
    }
}

Main函数里应该这样

饮水机 公司饮水机 = new 饮水机();
公司员工 我 = new 公司员工();

公司饮水机.饮水机没水了 += new 饮水机.饮水机没水了委托(我.换水);

for(int i=; i<10; i++)
{
    公司饮水机.出水(1);
    Thread.Sleep(1000);
}

Console.Read();

要注意的一点是:在“当饮水机没水了”函数内,应该判断“饮水机没水了”是否为null,否则就不要执行“饮水机没水了();”

四、事件例子的完整代码

//EventTest.cs
using System;
using System.Threading;

namespace ConsoleApp_CS
{
    public class 饮水机
    {
        private int 水量 = 10;
        public delegate void 饮水机没水了委托();
        public event 饮水机没水了委托 饮水机没水了;

        public void 出水(int 出水量)
        {
            Console.WriteLine("有人接水……");
            水量 -= 出水量;
            Console.WriteLine("桶里还剩{0}升水", 水量);
            if(水量 == )
            {
                当饮水机没水了();
            }
        }

        public void 当饮水机没水了()
        {
            if(饮水机没水了 != null)
            {
                Console.WriteLine("饮水机没水了,快来换水……");
                饮水机没水了();    //触发这个事件
            }
        }
    }

    public class 公司员工
    {
        public void 换水()
        {
            Console.WriteLine("我去换水,真累啊……");
        }
    }

    public class AppClass
    {
        public static void Main()
        {
            饮水机 公司饮水机 = new 饮水机();
            公司员工 我 = new 公司员工();

            公司饮水机.饮水机没水了 += new 饮水机.饮水机没水了委托(我.换水);

            for(int i=; i<10; i++)
            {
                公司饮水机.出水(1);
                Thread.Sleep(1000);
            }

            Console.Read();
        }
    }
}

参考:

Delegates and Events in C# / .NET

[整理]近段了解一些委托事件的工作原理.找到两个很不错的例子,所以特拿出与大家分享!