美文网首页
C#之delegate(委托)

C#之delegate(委托)

作者: 小羊爱学习 | 来源:发表于2024-04-16 12:57 被阅读0次
  • 声明方式
    // delegate <return type> <delegate-name> <parameter list>
    public delegate int CalculationDelegate(int a, int b);
    public class TestClass
    {

    }
  • 使用
     // 类外声明和使用
    // delegate <return type> <delegate-name> <parameter list>
    public delegate int CalculationDelegate(int a, int b);
    public class TestClass
    {
        //创建委托实例并赋值(静态实例)
        private static CalculationDelegate addDelegate = new CalculationDelegate(Add);
        //一个Void
        static int Add(int a, int b)
        {
            return a + b;
        }
        //测试调用委托
        public static void TestDelegate()
        {
            int result = addDelegate(5, 3);
            Console.WriteLine(result);
        }
    }
  • 不同作用域和实例使用
        // 类内声明和使用
        public delegate int CalculationDelegate(int a, int b);
        private void TestDelegate()
        {
            // 创建委托实例并赋值
            CalculationDelegate addDelegate = new CalculationDelegate(Add);
            int result = addDelegate(5, 3);
            Console.WriteLine(result);
        }
        int Add(int a, int b)
        {
            return a + b;
        }
     // 非静态声明
    // delegate <return type> <delegate-name> <parameter list>
    public delegate int CalculationDelegate(int a, int b);
    public class TestClass
    {
        //创建委托实例并赋值(非静态)
        public CalculationDelegate addDelegate = new CalculationDelegate(Add);
        //一个Void
        static int Add(int a, int b) 
        {
            return a + b;
        }
        //测试调用委托
        public void TestDelegate()
        {
            int result = addDelegate(5, 3);
            Console.WriteLine(result);
        }
    }
  • 跨文件使用:针对上图代码的延续
            var t = new TestClass();
            var r = t.addDelegate(1, 2);
            Console.WriteLine(r);
  • 特殊委托类型:除了普通委托,C#还提供了一些特殊的委托类型,如Action和Func。Action委托用于引用不返回值的方法,而Func委托用于引用具有返回值的方法。
        delegate void Action();

        delegate TResult Func<out TResult>();
        delegate TResult Func<in T, out TResult>(T arg);
eg:
        // 参数为string
        public Action<string> EventArgs;
        //参数一个为string,返回值为int。func定义中最后一个为返回值类型
        public Func<string,int> EventArgs;
  • 托编写一个回调函数(callback)
    A类文件:声明委托
    // delegate <return type> <delegate-name> <parameter list>
    public delegate void CallbackDelegate(string message);
    public class TestClass
    {
        public void PerformOperation(int value, CallbackDelegate callbackDelegate)
        {
            Task.Run(() =>
            {
                Task.Delay(8000).Wait();// 模拟操作延时
                if (callbackDelegate != null)
                {
                    callbackDelegate("返回值");
                }
            });
        }
    }

B文件:使用委托

        public FrmMain()
        {
            InitializeComponent();

            var test = new TestClass();
            CallbackDelegate callbackDelegate = new CallbackDelegate(MyCallbackFunction);
            test.PerformOperation(5, callbackDelegate);

        }
        void MyCallbackFunction(string message)
        {
            Console.WriteLine("回调函数被调用:" + message);
        }

因为之前是做ios开发,从ios的代理模式去理解出发,就改进了一下代码,这样更好理解两者的区别:c#中代理更灵活,代理方法不需要委托方定义,而是直接时让代理自己直接去定义实现了。

    // 声明代理
    public delegate void CallbackDelegate(string message);
    public class TestClass
    {
        // 将代理作为自己的属性
        public CallbackDelegate myDelegate;
        public void PerformOperation(int value)
        {
            Task.Run(() =>
            {
                Task.Delay(8000).Wait();// 模拟操作延时
                // 调用代理方法
                if (myDelegate != null)
                {
                    myDelegate("返回值");
                }
            });
        }
    }
        public FrmMain()
        {
            InitializeComponent();

            var test = new TestClass();
            test.myDelegate = new CallbackDelegate(MyCallbackFunction);
            test.PerformOperation(5);


        }
        void MyCallbackFunction(string message)
        {
            Console.WriteLine("回调函数被调用:" + message);
        }

由于项目中大多数用Action和Func这两个就足够应对了,所以我们还可以这样改进:

    public class TestClass
    {
        public Action<string> action;
        public void PerformOperation(int value)
        {
            Task.Run(() =>
            {
                Task.Delay(8000).Wait();// 模拟操作延时
                // 调用代理方法
                if (action != null)
                {
                    action("返回值");
                }
            });
        }
    }
        public FrmMain()
        {
            InitializeComponent();

            var test = new TestClass();
            test.action = MyCallbackFunction;
            test.PerformOperation(5);


        }
        void MyCallbackFunction(string message)
        {
            Console.WriteLine("回调函数被调用:" + message);
        }
  • 多播委托
     委托对象可以通过 ‘+’ 运算法进行组合,一个合并委托调用所组合的委托的所有指向方法引用地址,合并的委托必须是相同类型的。不仅是对象可以组合,通过 '+' 运算符可以让委托变量对方法自增。
            MyDelegate mydelegate1 = GetStr;
            MyDelegate mydelegate2 = GetStr;
            MyDelegate mydelegate3 = mydelegate1 + mydelegate2;
            MyDelegate mydelegate = GetStr;
            mydelegate += GetStr;

有增自然有减,可以通过 ‘-’ 运算符进行方法引用地址的剔除,如果有多个同样的方法,只删除其中一个。

using System;

delegate int NumberChanger(int n);
namespace DelegateAppl
{
   class TestDelegate
   {
      static int num = 10;
      public static int AddNum(int p)
      {
         num += p;
         return num;
      }

      public static int MultNum(int q)
      {
         num *= q;
         return num;
      }
      public static int getNum()
      {
         return num;
      }

      static void Main(string[] args)
      {
         // 创建委托实例
         NumberChanger nc;
         NumberChanger nc1 = new NumberChanger(AddNum);
         NumberChanger nc2 = new NumberChanger(MultNum);
         nc = nc1;
         nc += nc2;
         // 调用多播
         nc(5);
         Console.WriteLine("Value of Num: {0}", getNum());// num为75
         Console.ReadKey();
      }
   }
}
  • 匿名委托:
    我们之前的方法都是事先声明好了的,然后使用方法名。但是有时候我们不想要声明新方法,因为这个是一个临时的方法。那么就可以用在c# 2.0版本引入的匿名方法,或者是3.0以后版本的lambda表达式。

匿名方法使用的也是delegate关键字,不需要定义返回类型,格式为: delegate (传入参数) {执行语句},如下:

MyDelegate mydelegate = delegate(int i) { return i.ToString(); };

lambda表达式简化了匿名方法的书写,去掉了delegate关键字并加入 '=>' 运算符:

MyDelegate mydelegate = (int i) => { Console.WriteLine(i.ToString()); };
  • Event(事件):
    event和callback一样都是基于委托的封装,它用于建立一种通讯机制,使得对象可以通知系统某些事情已经发生,而无需知道具体会有哪些对象对此进行响应。

发布者与订阅者: 发布者负责声明和触发事件,订阅者负责订阅事件并定义响应逻辑。

事件订阅: 事件不能直接使用=,而是使用+=操作符订阅事件,-=操作取消事件订阅。也就是说发布者发布一个事件后,订阅者针对他只能进行自身的订阅和取消。

event+action

    public class TestClass
    {
        public event Action<string> MyEvent;
        public void PerformOperation(int value)
        {
            Task.Run(() =>
            {
                Console.WriteLine(value);
                Task.Delay(8000).Wait();// 模拟操作延时
                // 调用代理方法
                if (MyEvent != null)
                {
                    MyEvent("返回值");
                }
            });
        }
    }
        public FrmMain()
        {
            InitializeComponent();
            var test = new TestClass();
            test.MyEvent += MyCallbackFunction;
            test.PerformOperation(5);
        }
        void MyCallbackFunction(string message)
        {
            Console.WriteLine("回调函数被调用:" + message);
        }

但是,在事件发布和订阅的过程中,定义事件的原型委托类型常常是一件重复性的工作,因此EventHandler出生了

  • EventHandler:
    为了减少开发者重复性的定义event,.NET Framework 2.0推出了EventHandler,定义如下:
public delegate void EventHandler(object sender, EventArgs e);

我们通过一代代的代码来看一下它是如何被推出来的

 public class TestClass
 {
     //以下是推演演化过程 

     //1
     //public delegate void MyEventHandler(string str);
     //public event MyEventHandler EventArgs;

     //2
     //public event Action<string> EventArgs;// event+action// 相当于1

     //3
     //public delegate void MyDelegate(object sender, EventArgs e);
     //public event MyDelegate EventArgs;

     //4
     //public delegate void EventHandler(object sender, EventArgs e);
     //public event EventHandler EventArgs;//这个EventHandler是假的,和MyDelegate一样,是我们自己定义的名字

     //5
     //public event Action<object, EventArgs> EventArgs; // 相当于4

     //6 这个EventHandler才是系统提供的类,系统帮我们简化了4,直接出现了EventHandler类,我们就省去了自定义了
     public event EventHandler EventArgs;// 相当于5

     public void PerformOperation(int value, EventArgs e)
     {
         Task.Run(() =>
         {
             Console.WriteLine(value);
             Task.Delay(8000).Wait();// 模拟操作延时
             // 调用代理方法
             if (EventArgs != null)
             {
                 EventArgs("返回值", e);
             }
         });
     }
 }

调用

        public FrmMain()
        {
            InitializeComponent();
            var test = new TestClass();
            test.EventArgs += MyCallbackFunction;
            test.EventArgs += MyCallbackFunction2;
            test.PerformOperation(5, EventArgs.Empty);

        }
        void MyCallbackFunction(object sender, EventArgs e)
        {
            Console.WriteLine("回调函数被调用:" + sender.ToString());
        }
        void MyCallbackFunction2(object sender, EventArgs e)
        {
            Console.WriteLine("回调函数被调用2:" + sender.ToString());
        }

当然我们也可以自定义EventArgs ,继承于系统的EventArgs 就可以了,使用时把EventArgs 传递时改为我们自定义的子类就可以了,eg:

public class CustomEventArgs : EventArgs
{
    public CustomEventArgs(string message)
    {
        Message = message;
    }

    public string Message { get; set; }
}

相关文章

  • C# 委托

    C#委托 C#中的委托(Delegate)类似于C或C++中函数的指针。委托(Delegate)是存有对某个方法的...

  • C# 高级语言总结

    后续 1 C# 委托 委托(Delegate)特别用于实现事件和回调方法。所有的委托(Delegate)都派生自 ...

  • C#委托Delegate和事件Event实战应用

    一、委托的概念 C# 中的委托(Delegate)类似于 C 或 C++ 中函数的指针。委托(Delegate)是...

  • C# 委托(Delegate)

    C# 中的委托(Delegate)类似于 C 或 C++ 中的函数指针。委托(Delegate) 是存有对某个方法...

  • 19-委托

    C# 中的委托(Delegate)类似于 C 或 C++ 中函数的指针。 委托(Delegate) 是存有对某个方...

  • C#之delegate(委托)

    定义 委托是一个类,它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递,这种将方法动态地赋给参数的做...

  • C# 委托(delegate)

    委托是一种引用类型,可以将方法作为参数传递给其他方法,作为参数的这个方法可以是静态方法,实例方法,也可以是匿名方法...

  • C# delegate

    C# 中的 Delegate 类似于 C++ 中函数的指针。所有的委托Delegate都派生自 System.De...

  • 关于C#中的委托与事件以及两者之间的关系

    一 关于委托 1.委托的概念: C# 中的委托(Delegate)是一种引用类型变量,它类似于C的函数指针,...

  • 52个有效方法(23) - 通过委托与数据协议进行对象间的通信

    委托模式(Delegate pattern) 委托模式(Delegate pattern):用来实现对象间的通信 ...

网友评论

      本文标题:C#之delegate(委托)

      本文链接:https://www.haomeiwen.com/subject/ycerxjtx.html