编程语言
首页 > 编程语言> > c#图解教程_第十三章& 第十四章_委托和事件

c#图解教程_第十三章& 第十四章_委托和事件

作者:互联网

 

委托


 

定义:委托是持有一个或多个方法的对象,委托是类型,不是对象。

delegate是C#中的一种类型,它实际上是一个能够持有对某个方法的引用的类。与其它的类不同,delegate类能够拥有一个签名(signature),并且它"只能持有与它的签名相匹配的方法的引用"。

 

声明委托


 声明委托的三个步骤

  1. 声明一个delegate对象,它应当与你想要传递的方法具有相同的参数和返回值类型。
  2. 创建delegate对象,并"将你想要传递的函数作为参数传入"。
  3. 在要实现异步调用的地方,通过上一步创建的对象来调用方法。

PS:使用的是设计模式中的观察者模式

 

public void delegate MyDelegate();


public static void Main(){
     MyDelegate dele = new MyDelegate(TestFun);    
}

public void TestFun(){
  Console.WriteLine("Hello World");
}

 

事件


 定义:事件处理是一种特殊签名的委托

事件的本质是对委托的封装,类似属性是对字段的封装

事件MydelegateHandle 其实是对委托MyDelegate的一个实例,引发事件处理的通常被编写成一个函数

我们定义事件处理程序DelegateFun(),并把他注册到MydelegateHandle事件中

事件处理程序的参数应该和事件委托相同,一般情况下,事件处理程序接受两个参数,一个是事件的发送者Sender,一个是事件参数e,事件参数e用于在发送者和接受者之间传递消息

public delegate void MyEventHandle(object sender,MyEventArgs e);

public class EventTest{
   
    //定义委托
    public void delegate MyDelegate();
//定义事件 public event MyDelegate MydelegateHandle;
//定义事件发布者 public void GetEventHandle(){ Console.WriteLine("Test") if(MydelegateHandle!=null){ MydelegateHandle.Invoke(); } } } public class Demo{
   //定义事件触发方法 public void DelegateFun(){ Console.WriteLine("Hello EventHandle); } public static void Main(){ EventTest test = new EventTest(); test.MyDelegateHandle += Demo; //直接标书方法名,无需括号 test.GetEventHandle(); //输出 → Test Hello EventHandle } }

事件参数的设置:EventArgs 

public class EventTest{

    //定义委托
    public delegate void MyDelegate(object o,EventArges e);
   //定义事件,封装委托
   public event MyDelegate MyDelegateHandle;

   //定义事件发布者
   public void Demo(DemoEventArgs Dargs){
        Conosle.WriteLine($"{Dargs.number}");
         if(MyDelegateHandle!=null){
            MyDelegateHandle.Invoke(this,Dargs);
        }
   }
}

//自定义事件参数 public class DemoEventArgs:EventArgs{
public int number; public DemoEventArgs (int number){ this.number = number; } } public class Demo{ //设置事件接受者 public void AcceptEvent(object o,DemoEventArgs args){ Console.WriteLine($"Accept:{args.number}"); } } public class Test{ public static void Main(){ EventTest test = new EventTest(); test.MyDelegateHandle += new Demo().AcceptEvent; test.Demo(new DemoEventArgs(3)); } }
}

 

同步委托调用和异步委托调用


 委托的涉及到的涉及模式是观察者模式。

Observer设计模式是为了定义对象间一对多的依赖关系,以便于当一个对象改变状态时,其他依赖于他的对象会被自动告知并更新,观察者模式是一种松耦合的设计模式

大多数的委托的返回值都是void,原因是观察者设计模式本身就是松耦合的关系,发布者不关心谁订阅了事件,更不关心事件的返回值,所以大多数委托的范围值为空

 

订阅方法和取消订阅方法

public class Sender{
//定义委托
public delegate void MyDelegate();
//定义事件封装委托
public event MyDelegate MyDelegateHandle;

 //事件发布者
 public void SendMethod(){

//委托调用的方式是同步调用委托 if(MyDelegateHandle!=null){ MyDelegateHandle.Invoke(); } } }
//订阅客户端类 public class Demo{ public void TestOne(){ Console.WriteLine("TestOne"); } public void TestTwo(){ Console.WriteLine("TestTwo"); } } // public class DemoTest{ public static void Main(){ Sender sen = new Sender(); //订阅客户端,使用符号 "+=" 订阅客户端 sen.SendMethod += new Demo().TestOne(); sen.SendMethod += new Demo().TestTwo(); //取消订阅,使用符号 "-=",取消订阅客户端 sen.SendMethod -=new Demo().TestOne(); sen. SendMethod(); //输出结果 TestTwo; //每次只订阅一个客户端,使用符号“=” sen.SendMethod = new Demo().TestOne; sen.SendMethod(); //输出结果TestOne //每次使用 = 都相当于重新订阅客户端,而不是累加 sen.SendMethod = new Demo().TestTwo(); //输出结果TestTwo } }

同步调用委托 订阅的客户端会影响发布者所在的程序,当订阅的客户端发生异常,会将返回异常往上抛,使得程序异常结束,即时我们使用了catch块捕获了异常,但未执行的订阅者将不会继续执行

我们采取异步委托调用的方式,订阅的客户端不能影响事件的发布者,所以我们采取委托中的GetInvocationList的方法获取订阅的所有客户端的返回值

//不接受返回值
public void DoSomething() {
    // 做某些其他的事情
    if (MyEvent != null) {
        Delegate[] delArray = MyEvent.GetInvocationList();
        foreach (Delegate del in delArray) {                    
            try {
                // 使用DynamicInvoke方法触发事件
                del.DynamicInvoke(this, EventArgs.Empty);   
            } catch (Exception e) {
                Console.WriteLine("Exception: {0}", e.Message);
            }
        }
    }
}

//若订阅的方法具有返回值
public static object[] DoSomething(){
  //做某些事情
  if(MyEvent !=null){
     Delegate[] delArray = MyEvent.GetInvocationList();
     List<Object>  objList =  new List<Object>();
     foreach(Delegate method in delArray){
       try{  
           // 使用DynamicInvoke方法触发事件
            object obj = method.DynamicInvoke(args);
            if (obj != null)
               objList.Add(obj);
           }catch(exception ex){
               Console.WriteLine(ex.Message);
           } 
       }
    return objList.ToArray();
   }
}

//异步循环调用
public class Publisher {
public delegate void EventHandler();
    public event EventHandler MyEvent;
    public void DoSomething() {         
        // 做某些其他的事情
        Console.WriteLine("DoSomething invoked!");

        if (MyEvent != null) {
            Delegate[] delArray = MyEvent.GetInvocationList();

            foreach (Delegate del in delArray) {
                EventHandler method = (EventHandler)del;
                IAsyncResult asyncResult= method.BeginInvoke(null, EventArgs.Empty, null, null);
          object rtn = method.EndInvoke(asyncResult); //输出返回值,结束异步调用
            }
        }
    }
}

 

单个异步委托调用

public delegate  string MyDelegate3(string name);
public class Demo{
     
      public string DemoTest(string name){
           return name;
      }
}
public class Send{

      public static void Main(){
            MyDelegate3 delegate3 = new MyDelegate3(new Demo().DemoTest);
            IAsyncResult asyncResult=delegate3.BeginInvoke("Jack", null,null);  //异步调用
            string rtn = delegate3.EndInvoke(asyncResult); //输出返回值,结束异步调用
      }
}
            

 

标签:委托,c#,Demo,void,事件,第十三章,new,图解,public
来源: https://www.cnblogs.com/FrameCode/p/15080811.html