C# 委托,事件, 异步

2021-02-17 17:18

阅读:691

委托

? 委托可以说是方法的集合,里面放着方法列表,当调用的时候就会调用全部的方法列表

? 个人理解 :

  • 当声明和创建时委托时, 它是个 对象
  • 当使用委托,调用方法时,它是个 方法

声明委托类型

delegate void MyDel(int x)

对比一下filed字段声明

int  count = 5;

? 可以知道delegate 对应 int, 它是 种类型,void MyDel( int x ) 对应count

创建对象

private delegate void MyDel(int x);
MyDel requestHandler =new MyDel(addCount);


private void addCount(int x){
    x+=x;
}

为委托类型里面添加方法

requestHandler += addCount1;
requestHandler += addCount2;
//调用
requestHandler(5);

private void addCount1(int x){
  
}
private void addCount2(int x){
  
}

? 委托类型要是有返回值,那么最后一个方法执行的返回值就是就结果

委托方法内存放的是匿名方法

? 委托里的匿名方法的作用是初始化委托,就是方法列表中的方法是没有名字的

MyDel requestHandler;
requestHandler = delegate(int x){
    x+=x;
}

匿名方法捕获变量

? 从这里也可以知道匿名方法的声音应该是与int y =5 ;同级或是比它低层次

MyDel requestHandler;
int y=5;
requestHandler = delegate(int x){
    x=y+5;
}

委托 + lamb表达式

MyDel requestHandler;
MyDel requestHandler1;
//匿名方法
requestHandler = delegate(int x) {x+20;}
requestHandler1 =  x => {x+20;}

事件

? 联想一下观察者模式,当某一状态触发的时候,就会触发一些对象的方法,这个过程就像是委托一样调用方法列表一样,发布者就是一个委托对象,订阅者就是在里面的方法列表. 和方法,属性一样,事件event 是类或结构的成员,所以我们不能在一段可执行代码中声明事件,事件的初始值为null

? 个人理解:

  • event 的声明为事件的关键字,和方法,属性,字段平级

  • 当在调用时事件就是调用方法

?对于事件的私有委托, 需要注意的事项:

直接上代码

delegate void CountDel();
class Incrementer {
  //事件本身就是个观察者,一旦被触发,就马上通知订阅者
   public event CountDel  MyEvent;
  
  //这是某个触发点
  public void DoCount (){
    for(int i =1;i

标准事件(EventHandler)

? .NET 环境中定义的标准事件,定义如下:

public event delegate EventHandler (object sender , EventArgs args)

? 从形参名字可以看出第一个参数表示发送者,第二个参数传递一些信息

通过扩展EventArgs 来传递数据

? 需要配置泛型委托来实现,上代码

//自定义EventArgs
class MyEventArgs : EventArgs{
   public int Anum{
     get;set;
   }
}



class Incrementer {
  //事件本身就是个观察者,一旦被触发,就马上通知订阅者
   public event EventHandler  MyEvent;
  
  //这是某个触发点
  public void DoCount (){
    MyEventArgs eventArgs = new MyEventArgs();
    for(int i =1;i

异步

? 异步是什么 ? 例如你去买奶茶,店员说请稍等,你在店员做奶茶的同时,你可以刷刷朋友圈,做其他事,等奶茶做好了,你再付钱,完成了买奶茶这件事。对于我来说,店员调配奶茶就是一个异步方法。异步不一定就是在其他线程执行,也可能在同个线程执行

? 首先看一下异步方法

class Today{
    async Task MakeTeaAsync (){
        Console.Writeline("开始做奶茶呀!");
        Salewoman girl = new Salewomen();
        Tea tea = await girl.makeTea();
        return tea;
     }
}

class Test {
  public static void main(string args){
        Today  to = new Today();
        Task teaTask = to.MakeTeaAsync();
        Console.writeLine(teaTask.Tostring());
  }
    
}

? 异步方法有三种返回值void,Task,Task ,获取异步方法的结果调用Task.Result.调用方法的接收都是用Task 对象接收.

? 如果我们的异步不需要异步的数据,那么可以一直执行下去,但是当并行的线程需要异步的数据仍然会阻塞等待

class Test{
    public static void main (){
         Task task = CountAsync();
                 ...
         //下面需要用到异步的数据,那么加入异步没完成,此处会阻塞
         Console.wrintLine("结果为: "+task.Result);
      
        //异步方法另外两种返回值
        Task task = CounterAsync1();
        Task task = CounterAsync2();//或直接调用异步方法 CounterAsync();
    }
}

private async Task CountAsync(){
   int result = await SocketHelper.get();
   return result;
}

private async Task CountAsync1(){
    int result = await SocketHelper.getAgain();
    Console.writeLine("hello world !");
}

private async void CountAsync2(){
    int result = await SocketHelper.getAgain1();
}

? 那么有没有,解决方法呢?我就是不想阻塞. 有, 回调.稍后介绍

异步方法在新线程执行

? 异步默认情况下是当前线程执行的,当需要新开线程执行时,直接使用lamb 表达式

private async Task CountAsync(){
  
   int result = await Task.Run(new Fun(Get));
   //lamb表达式,
   int result1 = await Task.Run(()=>{
       return SocketHelper.get(num);
   });
  
   return result;
}

private int GetCount(int num){
    return SocketHelper.get(num);
}

? Task.Run( ) 返回的结果有TaskTask两种,形参用到的类有Action , FunFun,其中Fun不讲,详细方法如下 , (学习两种简单的)

public static Task Run (Action action) {}

public static Task Run (Func func) {}

? ActionFunc是两个委托, 它们的方法列表签名是不需要参数,返回值一个为void ,另外一个为传入的泛型,上面的例子

//委托Action 
 public delegate void Action();

//委托Func
public delegate TResult Func();

//创建匿名委托对象(方法列表)内添加Get方法
int result = await Task.Run(new Fun(Get));

? 假如我需要个执行的任务是需要传递参数的,那么可以这样写

int reusult = await Task.Run(()=>Get(5,6));

? 上面的例子()=>Get(5,6)是创建了Func对象,并且为这个委托(方法列表)内添加了一个匿名的不需参数的方法,在这个匿名方法内执行Get(5,6)

异步方法中取消任务

? 同样的是Task.Run( )方法,这里用到两个类,CancelationTokenCancelationTokenSource ,后者从名字可以看出是产生CancelationToken的,而使用CancelationToken去取消任务实际是令CancelationToken的属性IsCancelationRequestedtrue

public static Task Run (Action action , CancelationToken token) {}

public static Task Run (Func func , CancelationToken token ) {}
例子
class Test {
  public void main(){
     CancelationTokenSource source = new CancelationTokenSource();
     CancelationToken tokent = source.token;
      
     MyClass my = new MyClass();
     Task task = my.CancelAsync(token);
      
     //task.wait();
     //token.cancel;
     task.wait();
     Console.writeLine("结束");
  }
}

class MyClass {
  public async void CancelAsync(CancelationToken token){
    if(IsCancelationRequested)
            return;
    Task task = await Task.Run(new  Fun(TestTask),token);
    
  }
  
  public  void TestTask(){
     Console.writeLine("开始");
     for(int i = 0 ; i 
//带注释运行
开始
1 of counts is completed 
2 of counts is completed
3 of counts is completed
4 of counts is completed 
5 of counts is completed
结束
  
//不带注释运行
开始
1 of counts is completed 
2 of counts is completed
3 of counts is completed
结束

异步中处理异常

? await语句中直接加上try..catch

等待异步完成后再继续运行

//等待单个任务完成后继续执行
Task.Wait()
  
//等待一组任务完成后
Task[] tasks = new Task[]{t1,t2};
Task.WaitAll(tasks);

委托异步编程

? 当委托中只有一个方法(方法列表里只要一个方法)时可以使这个方法在另外的线程(线程池中的线程)中异步执行,使用的方法是委托的BeginInvoke ,当希望获取到异步的结果时可以检查BeginInvoke返回的IAsyncResultIscompleted属性,或是调用委托的EndInvoke来等待异步的完成.

namespace Common.Been
{


    internal delegate int MyDelegate(string milk, string tea);
    class Test
    {
        private MyDelegate del = delegate(string milk, string tea)
        {
            Console.WriteLine(milk + " " + tea);
            return milk.Length + tea.Length;
        };


        public void MyCallback(IAsyncResult asyncResult)
        {
            AsyncResult AsyncCallback = (AsyncResult) asyncResult.AsyncState;
            MyDelegate callDelegate = (MyDelegate) AsyncCallback.AsyncDelegate;
            int result = callDelegate.EndInvoke(asyncResult);
            //这里在进行一些其他操作
           
        }
        public void main()
        {
            string m = "cow milk";
            string t = "black tea";

            //public IAsyncResult BeginInvoke(string milk, string tea, AsyncCallback callback, object state) 
            //不使用回调的情况
            IAsyncResult AsyncResult = del.BeginInvoke(m, t, null, null);
            int result = del.EndInvoke(AsyncResult);

            //public delegate void AsyncCallback(IAsyncResult ar);
            //使用回调
            IAsyncResult AsyncResult1 = del.BeginInvoke(m, t, new AsyncCallback(MyCallback), del);
            

        }
    }

}

? BeginInvoke返回一个IAsyncResult对象,它实际上是个AsyhcResult对象,他们的关系是怎么样的呢?

? 其中,AsyncDelegate保持着调用BeginInvoke方法的委托引用,AsyncState保存着是BeginInvoke方法的第四个参数.

计时器

? 周期执行的异步类,同样它也是从线程池内拿取线程执行方法,同时可以传入回调

class Test {
    ///
    ///第二个参数: 传给回调的对象引用
    ///第三个参数: 多久后开始
    ///第四个参数: 每过多久循环
    public void main(){
            //public Timer( TimerCallback callback, object state, int dueTime, int period) 
            //public delegate void TimerCallback(object state);
            string giveCallback = "love you ";
            Timer timer = new Timer(new TimerCallback(TimeCallback), giveCallback, 2000, 3000);
      
    }
  
    private void  TimeCallback(object obj)
    {
            string whatYouGive = (string) obj;
    }
}


评论


亲,登录后才可以留言!