委托和事件

委托:就是一个能存放符合某种格式(方法签名)的方法指针的容器。

委托的作用:1.能将方法作为参数和返回值传递; 2.调用一个委托,执行N个方法(多播委托)。

/* 1.声明委托的本质:
     *  1.1委托编译后 生成一个 同名类(DGTest) 
     *  1.2继承关系: DGTest -> MulticastDelegate -> Delegate
     */
    public delegate void DGTest();

        private void btnTest_Click(object sender, EventArgs e)
        {
            //语法糖:在C#中有很多 简洁语法,实质是由编译器 在编译时 转成 完整语法,那么这种 简洁语法叫做语法糖
            //2.创建委托对象
            DGTest dg = Test;//new DGTest(this.Test);
            /*3.为委托追加方法的本质:
             *    是为 被追加的方法创建一个新的委托对象,并将 方法 指针存入对象的 父类的父类(Delegate)的 IntPtr 变量中
             *    然后再将 新创建的委托 添加到 当前委托对象(dg)的 数组中
             */
            dg += Test2;//编译后:(DGTest) Delegate.Combine(dg, new DGTest(this.Test2));
            dg += Test3;//编译后:(DGTest) Delegate.Combine(dg, new DGTest(this.Test3));
            dg -= Test3;//编译后:(DGTest) Delegate.Remove(dg, new DGTest(this.Test3));
            /*4.调用委托,其实就是通过调用委托对象里的Invoke方法 遍历 委托内部的数组,然后依次调用 数组中的 方法
             */
            dg();//编译后:dg.Invoke();
            
            /* 委托的作用:
             *   1.将方法做为参数
             *   2.将方法作为返回值
             */
        }

        void Test()
        {
            MessageBox.Show("Test");
        }

        void Test2()
        {
            MessageBox.Show("Test2");
        }

        void Test3()
        {
            MessageBox.Show("Test3");
        }

        #region 1.0 委托当参数
        private void btnPara_Click(object sender, EventArgs e)
        {
            InvokeTest(Test);
            InvokeTest(Test2);
            InvokeTest(Test3);
        }

        /// <summary>
        /// 委托当参数使用: 调用 3个 Test 方法 中的某一个
        /// </summary>
        /// <param name="strType"></param>
        public void InvokeTest(DGTest dgTest)
        {
            dgTest();
        } 
        #endregion

        #region 2.0 委托当返回值
        private void btnReturn_Click(object sender, EventArgs e)
        {
            DGTest dg = InvokeTest("1");
            dg();
        }

        /// <summary>
        /// 委托当返回值
        /// </summary>
        /// <param name="strType"></param>
        /// <returns></returns>
        public DGTest InvokeTest(string strType)
        {
            switch (strType)
            {
                case "1":
                    return Test;
                case "2":
                    return Test2;
                default:
                    return Test3;
            }
        } 
        #endregion

        #region 3.0 使用泛型方法 加 泛型委托 完成 通用版的 Max方法
        /// <summary>
        /// 使用泛型方法 加 泛型委托 完成 通用版的 Max方法
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnFindMax_Click(object sender, EventArgs e)
        {
            int[] arrInt = new int[5] { 1, 2, 5, 6, 3 };
            //int Max = MaxInt(arrInt);
            int max = MaxValue<int>(arrInt, (x, y) => x - y);

            string[] arrStr = new string[] { "a", "c", "b" };
            string maxLengthStr = MaxValue<string>(arrStr, (x, y) => x.Length - y.Length);

            Dog[] dogs = new Dog[] { new Dog() { age = 1, name = "小白" }, new Dog() { age = 0, name = "小白2" }, new Dog() { age = 5, name = "小白3" } };
            Dog maxAgeDog = MaxValue<Dog>(dogs, (x, y) => x.age - y.age);

        }

        int MaxInt(int[] arr)
        {
            int maxInt = arr[0];
            for (int i = 1; i < arr.Length; i++)
            {
                if (maxInt < arr[i])
                {
                    maxInt = arr[i];
                }
            }
            return maxInt;
        }


        T MaxValue<T>(T[] arr, Comparison<T> func)
        {
            T maxInt = arr[0];
            for (int i = 1; i < arr.Length; i++)
            {
                //使用委托来 完成元素 大小的比较过程!
                if (func(maxInt, arr[i]) < 0)
                {
                    maxInt = arr[i];
                }
            }
            return maxInt;
        } 
        #endregion

委托的缺点: 1.可以 Click=null 来清除所有注册的 事件; 2. 可以 Click() 来“假冒”事件的触发

解决 方案,把委托成员做成 private 的,然后增加 AddClickEventHandler RemoveClickEventHandler 两个 public 的方法。


事件:
对委托变量的可访问性进行控制封装。

例:利用事件自定义三击鼠标按钮方法
  public delegate void DGMyClick(DateTime time);   //定义委托

    /// <summary>
    /// 三击按钮类 - 用户点击三次后 执行用户的 方法
    /// </summary>
    public class MyTripleButton:System.Windows.Forms.Button
    {
        Timer time = new Timer();

        public MyTripleButton()
        {
            base.Click += MyTripleButton_Click;     //为父类的 单击事件 注册一个方法(就是 将一个 方法 存入 Click 属性中)
            time.Interval = 1000;
            time.Tick += time_Tick;
        }

        int clickTimes = 0;
        //定义一个 用来保存 用户方法的委托对象
        /*使用 事件event封装 委托变量,编译后:
         * 1.会把被修饰的委托变量私有化(private)
         * 2.会生成一个 与 委托变量 同名的 事件语法,内部包含 add 和 remove方法
         *                                        add 和 remove方法内部都是操作 私有的委托变量
         * 3.当外部访问 委托变量时,实际上访问的是 同名的事件语法,并使用 += 和 -= 为封装的 私有委托变量 增删方法
         */
        public event DGMyClick dgMyClick;

        void time_Tick(object sender, EventArgs e)
        {
            clickTimes = 0;
        }

        //每当被点击的时候,此方法会被调用
        void MyTripleButton_Click(object sender, EventArgs e)
        {
            //如果点击次数没达到3次
            if (clickTimes < 2)
            {
                //如果是第一次点击 则启动计时器
                if (clickTimes == 0)
                {
                    time.Start();
                }
                //点击次数++
                clickTimes++;
            }
            else//点击三次后
            {
                //1.执行用户的 方法
                if (dgMyClick != null)
                    dgMyClick(DateTime.Now);
                //2.清空点击次数
                clickTimes = 0;
                //3.重启计时器
                time.Stop();
            }
        }
    }

 
public Form1()
        {
            InitializeComponent();
            //1.创建三击按钮对象
            MyTripleButton myBtn = new MyTripleButton();
            //2.利用一个事件机制 为 按钮里的委托对象 注册一个 方法(或 移除一个方法)
            myBtn.dgMyClick += ClickSelf;
            //3.注意:因为使用了事件机制 封装了 按钮里的委托对象,所以不能 直接 赋值 和 调用委托了
            //myBtn.dgMyClick = null;
            //myBtn.dgMyClick();
            this.Controls.Add(myBtn);
        }

        void ClickSelf(DateTime time)
        {
            MessageBox.Show("三击了~~~~~~~~~~~~~!加分!");
        }



委托和事件的区别:委托时类,事件是用来封装“属性封装”的机制

就是一个能存放符合某种格就是一个能存放符合某种格式(方法签名)方法的指针的容器(方法签名)方法的指针的

就是一个能存放符合某种格式(方法签名)方法的指针的容器

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值