C#之委托和事件入门

C#之委托和事件入门

今天是新年开始上班的第一天,祝大家工作顺利。接下来我们一起来学习C#中的委托和事件。它们两个的关系非常密切,我们先从委托开始。

1 委托的定义、声明与调用
创建一个名为MyDelegate的控制台项目,并添加一个DelegateClass.cs。

 public delegate void NoReturnWithPara(int x, int y);//声明委托

声明委托和声明方法非常类似,只是在返回类型前添加一个delegate关键字。
该委托所对应的方法是带两个参数且无返回值的,所以在实例化时要注意方法的签名要与委托的声明一致。

//定义一个带两个参数无返回值的方法
private static void Plus(int x, int y)
 {
      Console.WriteLine(x + " " + y);
}
NoReturnWithPara methodPlus = Plus;  //实例化委托

需要说明的是,在实例化委托时,只需将方法名称赋值给委托即可,无需添加小括号和参数。

//另一种实例化委托的方法
NoReturnWithPara methodPlus = new NoReturnWithPara(Plus);

调用委托和调用一个方法是一样的

methodPlus(3, 4);  //调用委托

**2 利用委托解除耦合**

再添加一个GreetingClass.cs用来实现用不同的语言来打印问候语。
如果用普通方法,代码如下

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MyDelegate
{
	//代表不同国家类型的枚举变量
    public enum PeopleType
    {
        Chinese,
        English
    }

   public class GreetingClass
    {
    public static void SayHelloChinese(string name) //声明委托
       {
           Console.WriteLine("你好 " + name);
       }

       public static void SayHelloEnglish(string name)
       {
           Console.WriteLine("hello " + name);
       }
       public static void SayHello(string name, PeopleType type)
       {
           if (type == PeopleType.Chinese)
               SayHelloChinese(name);
           else
               SayHelloEnglish(name);
       }

   
    }
}

然后再Program.cs中调用相关方法

GreetingClass.SayHello("张三", PeopleType.Chinese);
GreetingClass.SayHello("Bob", PeopleType.English);

这样做虽然可以实现我们的功能,但如果要进行扩展就要修改SayHelloChinese()和SayHelloEnglis()两个方法,可以用委托来实现。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;


//利用委托解除耦合
namespace MyDelegate
{
   public delegate void GreetingHandle(string name);//声明委托

   public class GreetingClass
    {

       public static void SayHelloChinese(string name)        
       {
           Console.WriteLine("你好 " + name);
       }

       public static void SayHelloEnglish(string name)
       {
           Console.WriteLine("hello " + name);
       }

       //定义其中一个参数为委托类型(指代一个特定的方法,即把一个方法作为参数)
       //单一职责
       public static void SayHello(string name, GreetingHandle handle)
       {
           handle(name);  //调用这个特定的方法
       }

    }
}
 //实例化两个不同的委托 分别代表两个不同的方法
GreetingHandle chineseHandle = GreetingClass.SayHelloChinese; 
GreetingHandle englishHandle = GreetingClass.SayHelloEnglish;

GreetingClass.SayHello("张三", chineseHandle); //将委托作为方法的参数
GreetingClass.SayHello("Bob", englishHandle);

3 委托的多播
当实例化了一个委托后,这个委托变量中就包含了一个方法,还可通过+= 来向该委托变量中添加多个方法,当调用该委托变量时会按添加的顺序全部执行这些方法,当然这些方法的签名必须与委托的签名一致。

NoReturnWithPara methodPlus = Plus;  //实例化委托
NoReturnWithPara methodPlus = new NoReturnWithPara(Plus);

//委托的多播
 methodPlus += Plus;
 methodPlus += Plus; methodPlus += Plus;
 methodPlus += Plus;
 
//遍历该委托中的所有方法
foreach(var item in methodPlus.GetInvocationList())
{
     Console.WriteLine(item); //打印方法的名称
}

methodPlus(3, 4);  //调用委托中的所有方法

4 利用委托多播实现观察者模式
在该项目中添加多个类,代码如下

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MyDelegate
{
    //委托是一种类型 事件是委托类型的实例(某种类型的变量)

    public class Cat
    {
        public  void Miao()
        {
            Console.WriteLine("猫叫");
        }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MyDelegate
{
    public class Dog
    {
        public static void DogCall()
        {
            Console.WriteLine("狗叫");
        }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MyDelegate
{
    public class People
    {
        public static void Awake()
        {
            Console.WriteLine("人醒来");
        }
    }
}

要实现的功能是,当调用Cat类的Miao()时依次调用Dog类的DogCall()和People类的Awake()方法。若采用常规方法,可直接在Miao()方法中直接调用其它两个方法。

 public  void Miao()
        {
            Console.WriteLine("猫叫");
            Dog.DogCall();
            People.Awake();
        }

然后再Program中调用Miao()方法即可

Cat cat = new Cat();  
cat.Miao();

这样实现的弊端就是,如果在调用Miao()方法后,不仅要调用刚才所说的两个方法,还要调用其它方法,就要修改Cat类的Miao()方法,这样不利于类的封装,我们就可以通过委托来实现在调用Miao()方法时来确定后续要调用的方法,这样就更加灵活,即观察者模式。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MyDelegate
{
    public delegate void CatHandler(); //声明一个委托
    
    public class Cat
    {
        public CatHandler CatHandlerMethod; //实例化一个委托
        
        public  void Miao()
        {
            Console.WriteLine("猫叫");
            //Dog.DogCall();
            //People.Awake();


            if (CatHandlerMethod != null)
                CatHandlerMethod();   //执行委托
        }
    }
}

上述代码中的委托类型变量CatHandlerMethod所包含的方法是不确定的,在外部调用Miao()方法时,可动态地往该类的委托类型的成员变量CatHandlerMethod中添加方法。

 Cat cat = new Cat();  
//观察者模式
 cat.CatHandlerMethod += Dog.DogCall;
cat.CatHandlerMethod += People.Awake;  //为委托添加方法
           
cat.Miao();

5 事件与委托间的关系

委托是一种类型,而 事件是委托类型的实例(某种类型的变量),就是用委托来声明一个变量,这个变量就是事件。事件与委托的功能与用法类似,之所以要用委托来定义一个事件,就是为了安全。
接下来用事件来实现刚才的观察者模式

public class Cat
    {
        public event CatHandler CatHandlerEvent; //声明一个是事件
        
        public  void Miao()
        {
            Console.WriteLine("猫叫");
            //Dog.DogCall();
            //People.Awake();


            if (CatHandlerEvent != null)
                CatHandlerEvent();
        }
    }

声明事件只是比实例化委托时多了一个event关键字,接下就是在调用Miao()方法前为事件添加相应的方法

 Cat cat = new Cat();  
            
//为事件添加方法 事件不能用new来初始化,只能用+=来添加方法 发防止被赋值为null
//且事件不能在外部调用
 cat.CatHandlerEvent += Dog.DogCall;
 cat.CatHandlerEvent += People.Awake;
           
cat.Miao();

事件为了实现安全,它在委托的基础上又两个限制,第一个是不能用new
关键字来实例化一事件,用来防止一个事件被赋值为null。第二个是事件不能在外部被调用,即CatHandlerEvent 只能在Cat类中的被调用,不能在Program.cs中执行CatHandlerEvent ();语句,这样也保障了事件的安全性。

所以委托和事件之间的区别与联系就是:委托是类型,事件是委托的实例。

发布了19 篇原创文章 · 获赞 6 · 访问量 9433

猜你喜欢

转载自blog.csdn.net/u012712556/article/details/79354546