C#——Delegate(委托)与Event(事件)

C#——Delegate(委托)与Event(事件)

  • 前言
  • 一、Delegate(委托)
    • 1.是什么?
    • 2.怎么用?
      • Example 1:无输入无返回值
      • Example 2:有输入
      • Example 3:有返回值
      • Example 4:多播委托
      • Example 5:处理有返回值的多播委托的结果
  • 二、Event(事件)
    • 1.是什么?
    • 2.怎么用?
      • Example 1:简单案例
      • Example 2:流程中重复绑定同一方法的优化
  • 三、总结


前言

在刚开始学习C#的时候,常常委托与事件傻傻分不清,经常性的混为一谈。他们功能相似,应用场景却不太一样,下面就从分别的介绍再到差异的分析一起来看看啪。

一、Delegate(委托)

1.是什么?

委托是 C# 中的一种类型,它代表了对一个或多个方法的引用。它类似于函数指针,在编程中可以将方法作为参数传递给其他方法。

2.怎么用?

看个简单的委托应用:

例子是基于C#控制台编写的

Example 1:无输入无返回值

申明委托类型:

delegate void write();

定义一个委托变量:

        static write w;

写一个和申明的委托变量相同输入输出类型的函数:

        public static void writeS()
        {
            Console.WriteLine(1);
        }

给委托绑定方法并调用:

        static void Main(string[] args)
        {
            w += writeS;  //绑定
            w();		  //调用,会运行绑定的方法(writeS)
            Console.ReadKey();
        }

结果:
直接打印一个1。
在这里插入图片描述

Example 2:有输入

申明委托类型:

delegate void write(int a,int b);

定义一个委托变量:

        static write w;

写一个和申明的委托变量相同输入输出类型的函数:

        public static void writeS(int a,int b)
        {
            Console.WriteLine(a + b);
        }

给委托绑定方法并调用:

        static void Main(string[] args)
        {
            w += writeS;  //绑定
            w(1,2);		  //调用,会运行绑定的方法(writeS)
            Console.ReadKey();
        }

结果:
直接打印一个3。
在这里插入图片描述

Example 3:有返回值

申明委托类型:

delegate bool write(int a,int b);

定义一个委托变量:

        static write w;

写一个和申明的委托变量相同输入输出类型的函数:

        public static bool writeS(int a,int b)
        {
            return a > b;
        }

给委托绑定方法并调用:

        static void Main(string[] args)
        {
            w += writeS;  //绑定
            Console.WriteLine( w(1,2));		  //调用,会运行绑定的方法(writeS)
            Console.ReadKey();
        }

结果:
直接打印一个False。
在这里插入图片描述

Example 4:多播委托

在此讨论比较特殊的有返回值的多播委托
简单理解,就是把多个方法绑定到一个委托,委托触发将触发所有绑定的方法。

申明委托类型:

delegate bool write(int a,int b);

定义一个委托变量:

        static write w;

写一个和申明的委托变量相同输入输出类型的函数:

        public static bool writeS(int a,int b)
        {
            return a > b;
        }
        
        public static bool writeS2(int a,int b)
        {
            return a < b;
        }

给委托绑定方法并调用:

        static void Main(string[] args)
        {
            w += writeS;  //绑定
            w += writeS2;  //绑定
            Console.WriteLine( w(1,2));		  //调用,会运行绑定的方法(writeS和writeS2)
            Console.ReadKey();
        }

结果:
直接打印一个True。
在这里插入图片描述

此时可以注意到,我绑定了两个带返回值的方法,第一个(writeS)返回false,第二个(writeS2)返回true。实际页面打印的是True。多次测试后可以发现,当多播委托带有返回值时且有多个绑定方法时,返回值将以最后一个添加绑定的为最终结果。

Example 5:处理有返回值的多播委托的结果

为解决Example4中绑定多个返回值的方法时,可以在外部进行数据分析来获取最终的结果。

新增代码如下:

        static bool JudgeRet(int a,int b)
        {
            bool ret = true;
            if (w != null)
            {
                foreach (write item in w.GetInvocationList())//变量委托里面的所有绑定的方法列表,获取结果并处理结果
                {
                    ret = ret & item(a,b);//处理流程,有false就为false。
                }
            }
            return ret;
        }

完整代码如下:

    class Program
    {
        delegate bool write(int a,int b);
        static write w;
        static void Main(string[] args)
        {
            w += writeS;
            w += writeS2;
            Console.WriteLine(JudgeRet(1,2));
            Console.ReadKey();
        }

        static bool JudgeRet(int a,int b)
        {
            bool ret = true;
            if (w != null)
            {
                foreach (write item in w.GetInvocationList())
                {
                    ret = ret & item(a,b);
                }
            }
            return ret;
        }

        public static bool writeS(int a,int b)
        {
            return a > b;
        }

        public static bool writeS2(int a, int b)
        {
            return a < b;
        }
    }

结果:
有false则为false。
在这里插入图片描述

二、Event(事件)

1.是什么?

事件是一种特殊类型的委托,用于实现观察者模式。它限制了委托的使用,只允许外部类通过 += 和 -= 运算符订阅和取消订阅事件。它提供了一种安全的订阅机制,防止外部类直接调用委托列表。只有持有类可以触发事件。

本质上:事件是对委托的封装,提供了一种更安全、更封装的方式来进行观察者模式的实现。

2.怎么用?

Example 1:简单案例

全部代码以及解析:

    public delegate bool write(int a, int b);  //定义的委托类型

    public class test							//测试类,体现事件只能在持有类中触发
    {
        write w;								//委托对象

        public event write WriteEvent;			//事件对象
        
        public void triger(int a, int b)		//触发事件
        {
            WriteEvent?.Invoke(a, b);			//判断事件是否为空,不为空则触发
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            test t = new test();				//生成测试类实例
            //此时在外部,无法访问到委托实例w,只能通过事件WriteEvent绑定
            t.WriteEvent += writeS;				//绑定方法
            t.WriteEvent += writeS;
            t.WriteEvent += writeS;				//绑定了多次相同的方法
            t.WriteEvent += writeS;

            t.triger(1, 2);						//触发

            Console.ReadKey();
        }

        public static bool writeS(int a, int b)
        {
            Console.WriteLine(a + b);
            return a > b;
        }
    }

结果如下:

发现多次绑定同一方法时,无法判断重复,绑定几次执行几次。
在这里插入图片描述

上文需要注意的是,WriteEvent?.Invoke(a, b);直接调用了事件名,在简略声明中,可以 使用Invoke调用事件,但也仅限于事件拥有类内部使用。

Example 2:流程中重复绑定同一方法的优化

优化事件代码如下:

    public delegate bool write(int a, int b);

    public class test
    {
        write w;

        public event write WriteEvent
        {
            add
            {
                if (w != null && w.GetInvocationList().Contains(value))
                {
                    return;
                }
                w += value;
            }
            remove
            {
                w -= value;
            }
        }

        public void triger(int a, int b)
        {
            w(a, b);							//此处因为重写了Add以及Remove无法使用WriteEvent?.Invoke(a, b);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            test t = new test();
            t.WriteEvent += writeS;
            t.WriteEvent += writeS;
            t.WriteEvent += writeS;
            t.WriteEvent += writeS;
            t.triger(1, 2);
            Console.ReadKey();
        }

        public static bool writeS(int a, int b)
        {
            Console.WriteLine(a + b);
            return a > b;
        }
    }

结果:
在这里插入图片描述

三、总结

简单点:

  • 委托允许你将方法作为参数传递或存储,可以被直接调用。
  • 事件是一种特殊类型的委托,提供更安全、封装的订阅机制,只允许持有类触发事件(且必须是简单声明)。

你可能感兴趣的:(#,C#基础,c#,开发语言)