Delegate(委托)

在前面lambda章节中稍微提了一下委托,今天这章就让我们来深究一下委托。

委托的本质是一种类,他是继承MulticastDelegate类的。

而声明委托的关键字的delegate,如:public delegate void NoReturnNoParaOutClass();

但是刚才也讲了委托一种类,那按照类的声明,我们应该可以这样声明一个委托。

public class  NoReturnNoParaOutClass: System.MulticastDelegate
{ }

只不过由于这种类比较特殊,因为它由于框架限定,这种做法在.net框架中是不被允许的,所以我们只能通过delegate关键字来声明委托。

下面讲讲委托应该怎么用。

用委托分为三个步骤:

1)声明委托

2)委托实例化

3)委托的调用

public delegate void NoReturnNoPara();//1声明委托
NoReturnNoPara method = new NoReturnNoPara(this.DoNothing);//2 委托的实例化method.Invoke();//3 委托的调用

private void DoNothing()
        {
            Console.WriteLine("This is DoNothing");
        }

在前面的章节也讲过,实例化委托时必须保证委托的签名和方法的签名保持一致。

再说个例子来阐述委托的用法。

假设有一个这样的需求,有一个汽车工厂,生产一款汽车。按照一般的做法应该是这样的

 public void BuildCar()
        {
            Console.WriteLine("造一个发动机"); 

            Console.WriteLine("造一个外壳");

            Console.WriteLine("造一个底盘");

            Console.WriteLine("造四个轮子");

            Console.WriteLine("组装成一辆车");

            Console.WriteLine("造好了一辆车。。");
        }

但是由于社会在进步,车子的性能也在提升,车子的发动机也需要跟新换代,在以前只有自然吸气,现在需要增加 涡轮增压和电动,按照一般的改法的话。

  public void BuildCar(EngineType engineType)
        {
          if (engineType == EngineType.NaturalInspiration)
            {
               Console.WriteLine("造一个自然吸气发动机");
            }
            else if (engineType == EngineType.Turbo)
            {
              Console.WriteLine("造一个涡轮增压发动机");
            }
            else if (engineType == EngineType.Electric)
            {
               Console.WriteLine("造一个电池发动机");
            }

            Console.WriteLine("造一个外壳");

            Console.WriteLine("造一个底盘");

            Console.WriteLine("造四个轮子");

            Console.WriteLine("组装成一辆车");

            Console.WriteLine("造好了一辆GTR。。");
        }

 public enum EngineType
    {
        NaturalInspiration = 0,
        Turbo = 1,
        Electric = 2

    }

这种做法通过上端程序调用时传递一个参数来判断生产哪一种发动机。但是这样做对工厂的要求太大,万一以后出现了太阳能的岂不是对工厂的整体生产线都要进行修改,这样做的成本太大,不切合实际,而且现在的工厂一般都是只做组装工作,生产的任务都是外包出去。那么我们程序应该怎么改呢,毕竟程序源自于生活。要符合实际情况才行。

这个时候就需要使用委托了

我们把生产发动机都给剥离出来,在生产厂家只需要组装就行。

       public void BuildEngineNaturalInspiration()
        {
            Console.WriteLine("造一个自然吸气发动机");
        }
        public void BuildEngineTurbo()
        {
            Console.WriteLine("造一个涡轮增压发动机");
        }
        public void BuildEngineElectric()
        {
            Console.WriteLine("造一个电池发动机");
        }

那后再类中声明一个委托,并修改BuildCar方法。

 public void BuildCar(BuildEngineDelegate method)
        {
            method.Invoke();

            Console.WriteLine("造一个外壳");

            Console.WriteLine("造一个底盘");

            Console.WriteLine("造四个轮子");

            Console.WriteLine("组装成一辆车");

            Console.WriteLine("造好了一辆GTR。。");
        }

        public delegate void BuildEngineDelegate();

在上端调用时直接传递一个方法,内部调用一下完成组装,这样做生产厂家就不必考虑应该怎么做了,你调用的时候直接给我,而我这里就完成一个组装工作。

    CarFactory.BuildEngineDelegate method = new CarFactory.BuildEngineDelegate
    carFactory.BuildEngineNaturalInspiration);
    carFactory.BuildCar(method);

这样做厂家就对发动机怎么做的依赖性不那么强了。

再来讲个黑科技,有许多人写程序时不愿意写异常处理。在这里可以直接写一个异步处理,通过委托可以绑定在任何方法上。

        /// <summary>
        /// 通用的异常处理
        /// </summary>
        /// <param name="act">对应任何的逻辑</param>
        public static void SafeInvoke(Action act)
        {
            try
            {
                act.Invoke();
            }
            catch (Exception ex)//按异常类型区分处理
            {
                Console.WriteLine(ex.Message);
            }
        }

调用时只需要这样做就可以一步完成异步处理功能。

        CarFactory.SafeInvoke(() => carFactory.BuildCar(method));

最后在讲讲多播委托,提到多播委托就不得不提提设计模式中的观察者模式。

我们假设有一只猫叫了一声,然后狗叫,老鼠跑,小孩就哭了,妈妈也醒了。爸爸就大叫,邻居也被吵醒,小偷也赶快溜了。

就因为猫的叫,导致一系列的触发动作

    public class Cat
    {
        public void Miao()
        {
            Console.WriteLine("{0} Miao", this.GetType().Name);
            new Dog().Wang();
            new Mouse().Run();

            new Baby().Cry();
            new Mother().Wispher();
            new Brother().Turn();
            new Father().Roar();
            new Neighbor().Awake();
            new Stealer().Hide();

        }
    }

为了篇幅,其他类就不写上来了,都是简单的一些方法。。

假如猫叫一声,不是狗先叫,而是老鼠先跑,那岂不又要修改猫这个类,再说老鼠跑不跑管猫什么事,我叫我叫的,你爱干啥干啥,管我什么事,

但是这样的程序设计就必须修改猫这个类的方法。这个时候我们就要思考了,可不可把方法抽离出来,别那么依赖猫。其实用委托就可以实现这个功能。

声明一个委托,并在猫类中调用委托。

        public Action MiaoAction;

public event Action MiaoActionEvent;
                 public void MiaoEvent()
                  {
                     Console.WriteLine("{0} MiaoActionEvent", this.GetType().Name);
                     if (MiaoActionEvent != null)
                     MiaoActionEvent.Invoke();
  
                  }

这个上端调用只需要这样做。

                    Console.WriteLine("************cat.MiaoEvent();***********");
                    cat.MiaoActionEvent += new Dog().Wang;//订阅
                    cat.MiaoActionEvent += new Mouse().Run;
                    cat.MiaoActionEvent += new Baby().Cry;
                    cat.MiaoActionEvent += new Mother().Wispher;
                    cat.MiaoActionEvent += new Brother().Turn;
                    cat.MiaoActionEvent += new Father().Roar;
                    cat.MiaoActionEvent += new Neighbor().Awake;
                    cat.MiaoActionEvent += new Stealer().Hide;
                    cat.MiaoEvent();

  在上面中提到了Event关键字,它就是事件,那么委托和事件是怎样的关系呢。

委托是一种类型,而事件是委托的一个实例

其实事件控制了实例的使用权限,更加安全。

事件不能再其他类中调用,只能在声明事件的类中调用,这就保证了事件的安全。

在观察者模式中。分为发布者,订户,和订阅者。

在本例中,猫就是那个发布者,而狗、小孩就是订户,最后调用时,上端是订阅者。而事件的发布只能声明在引起这一系列动作类中。

那么使用委托的意义是什么呢,使用委托主要是为了解耦,是程序之间的依赖关系不是那么强。还有多线程,这个以后再讲。

  

 

时间: 2024-08-24 04:33:01

Delegate(委托)的相关文章

快速理解C#高级概念(一) Delegate委托

做.NET开发很久,最近重新温习<C#高级编程>一书.发现很多曾经似懂非懂的问题,其实也是能够慢慢钻研慢慢理解的. 所以,打算开写<C#高级编程系列>博文.其中会借鉴<C#高级编程>一书的概念,也会参照其他高手的博文,希望大家谅解.有不对的地方,欢迎指正. (另:本博文不会讲解定义,语法方面的基础知识.) 下面如题,我们来讲委托. Delegate委托,在.NET中应用的非常广泛.会涉及到Lambda表达式,事件,匿名方法等(请关注后续博文). 那么何为委托? 通俗的来

关于js模拟c#的Delegate(委托)实现

这是我的第一篇博文,想来讲一讲js的函数.我的标题是js模拟c#的Delegate. 一.什么是Delegate(委托) 在jquery中有delegate函数,作用是将某个dom元素的标签的事件委托给一个函数队列,在触发这个事件的时候会触发这个函数队列中的所有函数.而c#中的Delegate对象也是如此,将多个方法添加至一个委托对象,或称将多个方法委托给一个委托对象,当调用委托对象的Invoke方法时会调用所有被委托的方法.由此可以看出Delegate的本质应该是一个函数队列,执行委托对象就是

delegate委托的C++实现--C++11/14(原创)

熟悉C#的人都清楚delegate,也清楚委托的作用. 实现观察者模式,在C++中的一种做法就是通过接口继承来实现,这无疑大大增加了耦合度.通过delegate变可以解除这种耦合. 下面是上班时间,偷偷实现的一个我的delegate.直接上码: #include<list> #include<functional> #include<iostream> #include<string> #include<algorithm> using name

C#delegate委托

类似函数,却没有语句体. using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConsoleApplication3 { class Program { delegate double ProcessDelegate(double param1, double param2); //委托定义 sta

C# 匿名方法 委托 Action委托 Delegate委托

原文地址:https://msdn.microsoft.com/zh-cn/library/bb882516.aspx 匿名函数是一个“内联”语句或表达式,可在需要委托类型的任何地方使用. 可以使用匿名函数来初始化命名委托,或传递命名委托(而不是命名委托类型)作为方法参数. C# 2.0 引入了匿名方法,而在 C# 3.0 及更高版本中,Lambda 表达式取代了匿名方法,作为编写内联代码的首选方式. 实例参考: 1 using System; 2 using System.Collection

delegate委托事件(动态创建元素注册事件)

有这样一个小例子: <!--需求:给li里的a标签注册点击事件,并且点击"添加"按钮,新增li标签,新增的li里的a同样有注册事件--> <input type="button" id="btn" value="添加"/> <ul class="box"> <li> <a href="javascript:void(0)">点击

c# 通过delegate委托向主线程发送信息

c# windows编程,常会用到多线程,在新开的线程中要对主线程的页面数据进行更改时,需要通过delegate进行委托 public delegate void show(string info); //定义一个委托,参数为string private void add_info_event(string info) //定义一个方法,判断控件是否需要引用才可操作,将该方法与委托进行绑定,并用Invoke调用该委托和传递参数. { if (this.txb_info.InvokeRequire

delegate 委托

1 class Program 2 { 3 static void Main() 4 { 5 Class1 c1 = new Class1(); 6 c1.Start(); 7 } 8 } 9 10 class Class1 11 { 12 public static void Hello() 13 { 14 Console.WriteLine("Hello"); 15 } 16 17 public void Start() 18 { 19 Class2 c2 = new Class2

delegate委托的例子,实现对Form中控件的更新

using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; namespace In

delegate委托

public delegate void Del(); public delegate string DelStr(string name); class Program { static string Name = string.Empty; static void Main(string[] args) { //Del del = Test; //Del del = delegate() { }; //=>goes to 去执行 //Del del = () => { }; //DelSt