C#中委托的理解

时间:2021-01-02 19:28:28

  请注意,这只是个人关于C#中委托的一点点理解,参考了一些博客,如有不周之处,请指出,谢谢!

  委托是一种函数指针,委托是方法的抽象,方法是委托的实例。委托是C#语言的一道坎,明白了委托才能算是C#真正入了门。委托在c#中的应用特别的多,最常见比如事件监听器就是利用委托来实现的。我们点击winform上面的一个按钮,系统就会响应,这其实就是委托。

  为什么要用委托呢?绝对不是为了简单问题复杂化。我们知道在程序设计当中,数据结构和算法是非常重要的,但是在实际的开发当中,我们好像又不太用的着这些东西,这是因为我们使用的都是高级语言,想java、c#这一类的。这些高级语言在设计的时候已经帮我们把这些问题考虑进去了,所以我们才感觉不到算法和数据结构的存在。举个最简单的例子,我们常用的List、HshTable之类的都是java帮我们定义好了的数据结构。委托也是这样。委托的存在本质上是为了让代码解耦,实现代码的可维护和可扩展。

  我们就以点击一个按钮,然后触发一个事件为例来说明。

public void btnConfirmOnClick()
{
    FunctionA();
    FunctionB();
}

在上面的这段代码中,当一个按钮被点击的时候,就会去主动地调用FunctionA();FunctionB();这两个方法,这就完成了我们的任务啊。但是,当用户的需求发生见二连三的改变的时候,上面的代码就会被频繁的改动,比如说,要新增加一个FunctionC(),这样一来,说明上面这段代码距离工程实践的要求还有一定的距离。按照23种设计原则的要求,当代码的耦合性太大的时候,就要对代码进行拆分,怎么拆分呢?就是引入一个新的类C,当按钮被点击的时候,btnConfirmOnClick()这个方法去通知类C,C再去调用FunctionA();FunctionB();这些方法,这其实就是委托的设计思想。

  下面是一段委托的代码。

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

namespace DelegateTest
{
    class Program
    {
        static void Main(string[] args)
        {
            A a = new A(); // 定义按钮A

            B b = new B(a); // 定义响应事件B

            C c = new C(a); // 定义响应事件C

            // 按钮A被单击
            a.Raise("单击");

            // 按钮A被双击
            //a.Raise("双击");

            // 按钮A被三连击
            //a.Fall();

            Console.ReadLine();
            // 由于B和C订阅了A的事件,所以无需任何代码,B和C均会按照约定进行动作。
        }
    }

    /// <summary>
    /// 按钮A点击委托
    /// </summary>
    /// <param name="hand">点击:单击、双击</param>
    public delegate void RaiseEventHandler(string hand);
    /// <summary>
    /// 按钮A被三连击委托
    /// </summary>
    public delegate void FallEventHandler();
    /// <summary>
    /// 按钮A
    /// </summary>
    public class A
    {
        /// <summary>
        /// 按钮A点击事件
        /// </summary>
        public event RaiseEventHandler RaiseEvent;
        /// <summary>
        /// 按钮A被三连击事件
        /// </summary>
        public event FallEventHandler FallEvent;

        /// <summary>
        /// 点击
        /// </summary>
        /// <param name="hand">手:单击、双击</param>
        public void Raise(string hand)
        {
            Console.WriteLine("按钮A{0}点击", hand);
            // 调用点击事件,传入单击或双击手作为参数
            if (RaiseEvent != null)
            {
                RaiseEvent(hand);
            }
        }
        /// <summary>
        /// 被三连击
        /// </summary>
        public void Fall()
        {
            Console.WriteLine("按钮A被三连击");
            // 调用被三连击事件
            if (FallEvent != null)
            {
                FallEvent();
            }
        }
    }
    /// <summary>
    /// 响应事件B
    /// </summary>
    public class B
    {
        A a;

        public B(A a)
        {
            this.a = a;
            a.RaiseEvent += new RaiseEventHandler(a_RaiseEvent); // 订阅点击事件
            a.RaiseEvent += new RaiseEventHandler(a_RaiseEvent); // 订阅点击事件
            a.FallEvent += new FallEventHandler(a_FallEvent); // 订阅被三连击事件
        }
        /// <summary>
        /// 按钮点击时的动作
        /// </summary>
        /// <param name="hand">若按钮A被单击,则B攻击</param>
        void a_RaiseEvent(string hand)
        {
            if (hand.Equals("单击"))
            {
                Attack();
            }
        }

        /// <summary>
        /// 按钮被三连击时的动作
        /// </summary>
        void a_FallEvent()
        {
            Attack();
        }

        /// <summary>
        /// 攻击
        /// </summary>
        public void Attack()
        {
            Console.WriteLine("响应事件B响应");
        }
    }
    /// <summary>
    /// 响应事件C
    /// </summary>
    public class C
    {
        A a;
        public C(A a)
        {
            this.a = a;
            a.RaiseEvent += new RaiseEventHandler(a_RaiseEvent); // 订阅点击事件
            a.FallEvent += new FallEventHandler(a_FallEvent); // 订阅被三连击事件
        }
        /// <summary>
        /// 按钮点击时的动作
        /// </summary>
        /// <param name="hand">若按钮A被双击,则攻击</param>
        void a_RaiseEvent(string hand)
        {
            if (hand.Equals("双击"))
            {
                Attack();
            }
        }

        /// <summary>
        /// 按钮被三连击时的动作
        /// </summary>
        void a_FallEvent()
        {
            Attack();
        }
        /// <summary>
        /// 攻击
        /// </summary>
        public void Attack()
        {
            Console.WriteLine("响应事件C响应");
        }
    }

}