黑马程序员——04 委托和事件

本文详细介绍了.NET编程中的委托和事件。首先讲解了委托的概念,它是一种封装方法的类型,允许在运行时调用不同的方法。接着讨论了委托的声明、返回值类型、方法参数匹配规则以及如何实例化和注册方法。然后转向事件,解释了事件作为信号机制的用途,如何声明事件、注册和移除事件处理程序。最后,阐述了委托和事件之间的关系,强调事件是特殊形式的委托。
摘要由CSDN通过智能技术生成

------- Windows Phone 7手机开发.Net培训、期待与您交流! -------

——委托

什么是委托:

委托是一种用于封装方法的类型,是一个能够引用方法的对象,能够调用它所指向的方法,在程序运行期间,同个委托可以调用不同的方法,委托是委托类型的实例

委托的基类:

 System.Delegate类,其本身不是委托类型,且不允许显式的直接从该类派生新的类型

  声明委托:

 创建一个协定,该协定指定一个或多个方法的签名

引用静态方法或者实例方法

声明委托需要使用delegate关键字 

语法:

访问修饰符 delegate返回值类型(方法参数)

访问修饰符:

Public表示该委托是公开的,访问不受限制

Protected表示该委托只能是本身委托访问

Internal:表示该委托只能是在当前应用程序中访问

Private表示该委托只能是本身访问

(注意:只有在其他类型中声明委托时,才能够使用new修饰符,它表示所声明的委托会隐藏具有相同名称的继承成员

 返回值类型:

返回值类型和传入的方法共同确定方法的返回类型,方法名,方法参数

例如:

publicdelegateintMyDelegate(int i,int j);//声明委托MyDelegate

(注意:委托类型是默认从System.Delegate派生的类类型,它隐含为密封类型化,因此不能从委托类型派生一个新的类型)

向委托注册方法:

委托声明好以后,就需要给委托添加方法列表,使得创建对象后可以依次执行各个方法

注册方法到委托时,该方法的签名必须和该委托的所指定的签名完全匹配

 匹配规则:

a).方法返回类型必须和委托的返回类型相同

b).方法的方法参数必须和委托的的方法参数相同,参数的具体名称可以不相同

例如:

声明五个方法:F1,F2,F3,F4,F5,判断它们能否注册到MyDelegate委托中

publicvoid F1(int i, int j);//不能,原因:返回值类型与MyDelegate委托不相同

publicvoid F2(int i);//不能,原因:返回值类型和方法参数个数与MyDelegate委托不相同

publicint F3(int i);//不能,原因:方法参数个数与MyDelegate委托不同

publicint F4(int i,int j);//能

publicint F5(int j,int i);//能

实例化委托:

委托是一个类,因此,委托需要实例化。

委托实例化可以创建委托类型的实例,并向该实例注册方法列表

 委托类型的实例的方法列表可以为静态方法,实例方法或者另外一个委托实例

(注意:委托实例化,它把静态方法,实例方法或者另外一个委托的名称作为该实例的参数进行传递)

例如

namespace 实例化委托 {        public delegate int MyDelegate(int i);//声明一个委托:名称为MyDelegate返回类型为int,方法参数为int i        class Program//声明一个类:名称为Program,类中有一个实例方法F1(inti),一个静态方法F2(int i)     {         public int F1(int i)         {             Console.WriteLine("调用了一个实例方法F1(int i)");             return i;         }         public static int F2(int j)         {             Console.WriteLine("调用了一个静态方法F2(int j)");             return j;         }         static void Main(string[] args)         {             Program p = new Program();//实例化program类为p,             MyDelegate d1 = new MyDelegate(p.F1);//d1注册p的实例方法F1             int i = d1(10);             Console.WriteLine("i的值为" + i);             MyDelegate d2 = new MyDelegate(Program.F2);//d2注册program的静态方法F2             int j = d2(20);             Console.WriteLine("j的值为" + j);         }     } }

结果:

 

构建委托的方法列表:

使用委托可以将多个方法绑定到同一个委托变量中。

当调用此变量时,可以一次调用所有绑定的方法。

每个委托实例都必须包含其方法列表,方法列个表可以包含一个或多个方法

委托实例除了在其实例化时注册方法之外,还可以通过“+””+=”运算符向该实例的方法列表中注册方法,通过“-”或者“-=”运算符从该实例的方法列表中移除方法

例如:

namespace test {        public delegate int MyDelegate(int i);//声明一个委托:名称为MyDelegate返回类型为int,方法参数为int i        class Program//声明一个类:名称为Program,类中有两个静态方法F1(inti),F2(int i)     {         public static int F1(int i)         {             Console.WriteLine("调用了一个实例方法F1(int i)");             return i;         }         public static int F2(int i)         {             Console.WriteLine("调用了一个静态方法F2(int j)");             return i;         }        static void Main(string[] args)         {  //创建MyDelegate委托的5个实例:d1,d2,d3,d4,d5             MyDelegate d1 = new MyDelegate(Program.F1);//d1调用program类的F1方法             MyDelegate d2 = new MyDelegate(Program.F2);//d2调用program类的F2方法             MyDelegate d3 = d1 + d2;//d3一次调用program类的F1,F2方法             MyDelegate d4 = d1 + d2 + d3;//d4一次调用program类的F1,F2,F2,F1             MyDelegate d5 = d4 - d2;//d5一次调用program类的F1,F2,F1方法             int i1 = d1(20); Console.WriteLine("i1的值为" + i1);             int i2 = d2(20); Console.WriteLine("i2的值为" + i2);             int i3 = d3(20); Console.WriteLine("i3的值为" + i3);             int i4 = d4(20); Console.WriteLine("i4的值为" + i4);             int i5 = d5(20); Console.WriteLine("i5的值为" + i5);             Console.ReadKey();         }     }

结果

分析:

d1d2通过“+”运算符得到d3

d1d2d3通过“+”运算符得到d4

d4-d2得到d5,即表示从d4的方法列表的末端开始查找,如果该方法被包括在d2实例的方法列表中,则从d4的方法列表中移除该方法

调用委托:

委托是一个方法链条,因此调用我欸托实例就相当于调用了该委托实例包含的所有方法

如果一个调用列表包含多个方法时,当该委托实例被调用时,它将按照调用列表中方法的注册顺序依次调用每一个方法

例如:

namespace 构建委托的方法列表 {     public delegate void MyDelegate(int i);//声明一个委托:名称为MyDelegate,返回类型为void,方法参数为int i     class Program//声明一个类:名称为Program,内有两个静态方法F1(inti),F2(int i)     {         public static void F1(int i)//F1(int i):输出“Program.F1:参数i的值“         {             Console.WriteLine("Program.F1:" + i.ToString());         }         public static void F2(int i)//F2(inti):输出”Program.F2:参数i的值“         {             Console.WriteLine("Program.F2:" + i.ToString());         }               static void Main(string[] args)         {             MyDelegate d1 = new MyDelegate(Program.F1);//d1调用F1             MyDelegate d2 = new MyDelegate(Program.F2);//d2调用F2             MyDelegate d3 = d1 + d2;//d3依次调用F1,F2             MyDelegate d4 = d3 + d2 + d1;//d4一次调用 F1,F2,F2,F1             MyDelegate d5 = d4 - d2;//d5调用F1,F2,F1             d1(10); Console.WriteLine();             d2(200); Console.WriteLine();             d3(3000); Console.WriteLine();             d4(40000); Console.WriteLine();             d5(500000); Console.WriteLine();             Console.ReadKey();         }     } 

结果:

分析:

d1(10);调用了d1实例,并调用和了F1方法。

d2(200);调用了d2实例,并调用了F2方法

d3(3000);调用了d3实例,并依次调用了F1,F2方法

d4(40000);调用了d4实例,并依次调用了F1,F2,F2,F1方法

d5500000);调用了d5实例,并依次调用了F1,F2,F1方法

——事件

什么是事件:

 某些操作发生时自动地放出的通知,它是一种信号机制

程序员可以通过提供事件处理程序,为相应的事件添加可执行代码。

当触发事件时,将调用该事件实现定义的方法

声明事件:

事件同委托一样,使用之前需要声明

它包含两个参数:指示事件源的对象源参数和封装事件的其他任何相关信息的e参数

其中e参数的类型为System.EventArgs或从System.EventArgs类派生的类型

步骤:声明事件的委托—>声明事件的本身

例如:

声明事件的委托:

1.EventHander包含两个参数:sender和e,其中sender表示事件源,e表示与该事件相关的信息

publicdelegatevoidEventHandler(object sender,EventArgs e);

声明事件的本身

2.在类中声明事件Print,它的类型为EventHandler

publicevent EventHandler Print;

注册事件

事件同委托一样,需给事件注册方法列表

一个事件声明之后,该事件的默认值为null

如果希望该事件继续执行事先指定的操作,则首先向该事件注册方法列表(即委托的调用列表)

注册事件可以用”+=“运算符

例如:

namespace 注册事件 {     public delegate void EventHandler(object sender, EventArgs e);     class Program     {         public event EventHandler Print;//声明事件Print         public void F(object sender, EventArgs e)         {             Console.WriteLine("调用方法F");         }         static void Main(string[] args)         {             Program p = new Program();            p.Print += new EventHandler(p.F);            if (p.Print != null)//判断是否为空             {                p.Print(null, null);             }            Console.ReadKey();         }     } } 

移除事件

移除事件使用”-=“运算符来实现

例如:

namespace 移除事件
{
    public delegate void EventHandler(object sender, EventArgs e);
    class Program
    {
        public event EventHandler Print;//声明事件Print
        public void F1(object sender, EventArgs e)
        {
            Console.WriteLine("调用方法F1");
        }
        public void F2(object sender, EventArgs e)
        {
            Console.WriteLine("调用方法F2");
        }
        static void Main(string[] args)
        {
            Program p = new Program();
            p.Print += new EventHandler(p.F1);
            p.Print += new EventHandler(p.F2);
            if (p.Print != null)//判断是否为空
            {
                p.Print(null, null);
            }
            Console.WriteLine();
            p.Print -= new EventHandler(p.F1);//移除F1事件
            if (p.Print != null)//移除F1后的输出列表
            {
                p.Print(null, null);
            }
            Console.ReadKey();
        }
    }
}

调用事件

声明一个事件之后,如果没有向该事件注册方法,那么该事件的值为空(null

因此,在调用事件时,往往需要检查该事件是否为空

例如:

namespace 调用事件 {     public delegate void EventHandler(object sender, EventArgs e);     class Program     {         public event EventHandler Print;//声明事件Print         public void F1(object sender, EventArgs e)         {             Console.WriteLine("调用方法F1");         }         static void Main(string[] args)         {             Program p = new Program();             p.Print += new EventHandler(p.F1);             Console.WriteLine("事件中的方法列表");             if (p.Print != null)//判断是否为空             {                 p.Print(null, null);//调用事件             }             Console.ReadKey();         }     } }

——委托和事件的关系

事件是一种特殊的委托

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值