zoukankan      html  css  js  c++  java
  • Net学习日记_委托事件

     

    一、委托

    1.概念:用来存放 方法 指针(地址)的容器。

    为什么要有委托?

    当有的业务代码总体已经实现,但有部分需要调用者来决定,就可以使用委托的方式,让调用者把一段代码以 方法的方式 传入。

    List<Person> list2 = new List<Person>();
    list2.Add(new Person());
    list2.Add(new Person());
    list2.Add(new Person());
    //平时,我们每次需要遍历集合的时候都要手写 循环代码
    foreach (Person per in list2)
    {
        Console.WriteLine(per.SayHi());
    }
    //使用 集合的 ForEach方法,它会帮我们 遍历 list2里的元素,但是它不知道每次遍历要对元素做什么事情,
    //需要程序员传入代码(执行代码只能放在方法里,所以这里需要传入一个方法)。
    list2.ForEach(TakeSayHi);
    //准备给ForEach的方法
    public void TakeSayHi(Person p) 
    {
          Console.WriteLine(p.SayHi());
    }

    【问题】:方法是如何传递的呢?

    通过 委托类!

    2.1简单实用

    2.1.1如何定义委托

    public delegate void DGSayHi(Person p);

    2.1.2如何创建委托对象

    //定义方法(其签名必须与 要添加到的委托 的签名一致)
    public void TakeSayHi(Person p)
    {
        Console.WriteLine(p.SayHi());
    }
    
    //创建委托对象(构造函数中传入方法)
    DGSayHi dgSayhi = new DGSayHi(TakeSayHi);

    2.1.3如何调用委托

    //1.创建委托对象,传入 与委托具有相同签名的方法
    DGSayHi dgSayhi = new DGSayHi(TakeSayHi);
    //2.调用委托里的方法,并为委托里的方法 传入参数
    dgSayhi.Invoke(new Person());

    2.2将方法当参数(本质是把委托当参数,委托里存放要传递的方法)

    //定义需要传递委托参数的方法:
    public void TestDGSayHI(DGSayHi dgSayHI)
    {
        Person p = new Person();
        dgSayHI.Invoke(p);//通过委托调用随委托传进来的方法
    }
    
    //测试:
    DGSayHi dg = new DGSayHi(TakeSayHi);
    //把方法存在委托中 ,然后 传递给 调用方法
    TestDGSayHI(dg);

    2.3将方法当返回值(本质是把委托当返回值,委托里存放要返回的方法)

    public DGSayHi CreateDele(string type) {
        switch (type)
        { 
            default:
                return new DGSayHi(TakeSayHi);
        }
    }
    调用: Person p
    = new Person(); //返回一个 包含了 方法的委托对象 DGSayHi dg = CreateDele("p"); //通过委托 调用委托里的方法 dg.Invoke(p);

     

    2.4向委托中存放多个方法(多播委托)

    DGSayHi dgSay = new DGSayHi(TakeSayHi);
    //向委托中 追加 方法(也存在委托中)
    dgSay += new DGSayHi(TakeSayHiInJp);
    dgSay += new DGSayHi(TakeSayHiInKr);
    //调用的时候 会 按照方法添加的顺序 依次执行方法 并为 每个方法都传入相同 的 参数
    dgSay.Invoke(new Person());

    2.5移除委托中的方法

    DGSayHi dgSay = new DGSayHi(TakeSayHi);
    //向委托中 追加 方法(也存在委托中)
    dgSay += new DGSayHi(TakeSayHiInJp);
    dgSay += new DGSayHi(TakeSayHiInKr);
    //移除委托中的 一个方法
    dgSay -= new DGSayHi(TakeSayHiInJp);
    //调用委托中 剩下的两个方法,并传入 相同参数
    dgSay.Invoke(new Person());

    3.语法糖

    为了简化语法,.Net编译器会认识一些简单的语法,并在编译的时候转成正常语法代码。因为是在编译的时候替换,所以不会影响运行的效率。

    //3.1创建委托 和 执行委托里的方法的  语法糖
    DGSayHi dgSayHi2 = TakeSayHi;//new DGSayHi(TakeSayHi);
    dgSayHi2(new Person());//dgSayHi2.Invoke(new Person())
    
    //3.2直接把方法 作为参数 传入
    TestDGSayHI(TakeSayHi);// TestDGSayHI(new DGSayHi(this.TakeSayHi));
    
    //3.3+= / -=
    DGSayHi dgSay2 = TakeSayHi;
    dgSay2 += TakeSayHiInJp;
    dgSay2 += TakeSayHiInKr;
    dgSay2 -= TakeSayHiInJp;
    dgSay2(new Person());
    编译后: DGSayHi dgSay2
    = new DGSayHi(this.TakeSayHi); dgSay2 = (DGSayHi) Delegate.Combine(dgSay2, new DGSayHi(this.TakeSayHiInJp)); dgSay2 = (DGSayHi) Delegate.Combine(dgSay2, new DGSayHi(this.TakeSayHiInKr)); dgSay = (DGSayHi) Delegate.Remove(dgSay, new DGSayHi(this.TakeSayHiInJp)); dgSay2.Invoke(new Person());

     语法糖:C# 中有很多简介语法,实质是由编译器在编译时转成完整语法,那么这种简洁语法叫做语法糖。

    注意:方法中不能定义类
    private void btnDelSelf_Click(object sender, EventArgs e)
    { 
    //class A{}
    //delegate void A();//而 委托 就是在一个 类,所以也不能在方法中定义委托
    }

    4.委托原理

    4.1定义委托:

    public delegate void DGSayHi(Person p);

    编译后:会生成一个继承于 MulticastDelegate 的类!

    .class public auto ansi sealed DGSayHi
        extends [mscorlib]System.MulticastDelegate
    {
    .method public hidebysig newslot virtual instance void Invoke(class 委托事件.Person p) runtime managed
    ......
    }

    声明委托的本质:

    1.委托变异后,生成一个同名类

    2.编译后我们看到了一个继承关系: 自定义委托类 -> MulticastDelegate ->Delegate

    4.2委托类 Delegate

    委托追加方法的本质:

    视为被追加的方法创建一个新的委托对象,并将方法指针存入对象的父类的父类(Delegate)的IntPtr变量中,然后再将新创建的委托添加到当前委托对象(dg)的数组中。

     

    调用委托,其实就是通过调用委托对象里的Invoke方法,遍历 委托内部的数组,然后依次调用数组中的方法。

    委托的作用:1.将方法作为参数。2,将方法作为返回值。

    5.匿名方法

    针对于某些只调用一次的方法,使用匿名方法。

    List<Person> list2 = new List<Person>();
    list2.Add(new Person());
    list2.Add(new Person());
    list2.Add(new Person());
    //匿名方法
    list2.ForEach(delegate(Person p)
    {
        Console.WriteLine(p.SayHi());
    });

     

     

    二、事件 Event

    为什么要有事件?

    如果所有地方都是用委托,那么有可能发生这种情况:一个委托对象,已经注册了若干方法,但某个程序员不知道,直接将委托 设置为 null,清空了所有的方法。

    而事件 可以 为我们限制在外部访问某个类里的 委托对象 的方式,只能在外部通过 +=/-=操作委托对象。

     

    1.语法

    //1.先定义委托 类
    public delegate void DGTripleClick();
    //2.定义事件(在某个类中需要使用委托时,加个event关键字)
    public event DGTripleClick TripleClickEvent;
    //3.使用事件
    TripleClickEvent += Mehtod1;
    TripleClickEvent -= Mehtod1;
    TripleClickEvent=null;//报错,事件委托在外部只能在 +=/-=左边
    TripleClickEvent();//报错,事件委托在外部不能直接调用执行

    2.原理

    C# 里的事件 其实是一套类似于 属性的 语法机制

    用来 限制 在某个类的外面 访问 类里面的 委托的 方式。

    事件会在编译后 自动的生成一个私有的委托变量,同时生成 addon 和 removeon 两个公有的 两个方法用来 +=/-= 操作 这个私有委托变量。    

     

  • 相关阅读:
    UOS、鸿蒙、麒麟全面出击,国产系统能否干掉Windows?
    黑客给疫情添乱
    人工智能与信息安全
    作为一个程序员,告诉你一些编码知识
    Linus Torvalds 宣布新版Linux系统内核发布
    linux系统root密码忘记了怎么办
    DevOps与NoOps现状分析
    Nginx服务详细介绍
    博客园“可运行"代码
    让setTimeout支持链式
  • 原文地址:https://www.cnblogs.com/lisong-home/p/7865690.html
Copyright © 2011-2022 走看看