您的位置:新葡亰496net > 奥门新萄京娱乐场 > 委托和事件

委托和事件

发布时间:2019-08-02 13:07编辑:奥门新萄京娱乐场浏览(112)

    以下都是自家在网络征集下来的认为到是比较易懂,优秀的。

    寄托给了C#操作函数的灵活性,我们可采纳委托像操作变量一样来操作函数,其实那些功用并不是C#的创始,早在C 时代就有函数指针这一说法,而在笔者眼里委托便是C#的函数指针,首先先简要的介绍一下委托的基本知识:

     

    寄托给了C#操作函数的灵活性,大家可接纳委托像操作变量同样来操作函数,其实这一个功效并非C#的首创,早在C 时期就有函数指针这一说法,而在我眼里委托便是C#的函数指针,首先先简要的介绍一下寄托的基本知识:

    信托的概念 委托的宣示原型是 
    delegate <函数重临类型> <委托名> (<函数参数>)
    事例:public delegate void CheckDelegate(int number);//定义了一个委托CheckDelegate,它能够挂号再次来到void类型且有一个int作为参数的函数
    如此那般就定义了多少个信托,不过委托在.net内一定于注明了多个类(在前边的代码中会讲到确实那样),类固然不实例化为目的,比相当多功能是从未艺术使用的,委托也是如此.

    信托的实例化 委托实例化的原型是
    <委托项目> <实例化名>=new <委托项目>(<注册函数>)
    例子:CheckDelegate _checkDelegate=new CheckDelegate(CheckMod);//用函数CheckMod实例化下边包车型地铁CheckDelegate 委托为_checkDelegate
    在.net 2.0起始能够直接用特别的函数实例化委托:
    <委托项目> <实例化名>=<注册函数>
    例子:CheckDelegate _checkDelegate=CheckMod;//用函数CheckMod实例化上边的CheckDelegate 委托为_checkDelegate
    现今大家就能够像使用函数一样来选拔委托了,在地点的例证中未来施行_checkDelegate()就一样施行CheckMod(),最注重的是前几日函数CheckMod相当于位于了变量其中,它能够传递给另外的CheckDelegate援用对象,并且可以视作函数参数字传送递到任何函数内,也足以当做函数的回到类型

     

    用佚名函数开首化委托

    下面为了开头化委托要定义一个函数是还是不是深感微微劳苦,别的被给予委托的函数一般都以经过信托实例来调用,相当少会平昔调用函数本身。

    在.net 2.0的时候思索到这种气象,于是无名氏函数就出生了,由于无名氏函数没著名字所以必供给用三个委托实例来援引它,定义无名函数便是为了初阶化委托

    无名氏函数开首化委托的原型:

    <委托项目> <实例化名>=new <委托项目>(delegate(<函数参数>){函数体});

    本来在.net 2.0后方可用:

    <委托项目> <实例化名>=delegate(<函数参数>){函数体};

    例子:

    新葡亰496net 1

            delegate void Func1(int i);
            delegate int Func2(int i);

            static Func1 t1 =new Func1(delegate(int i)
            {
                Console.WriteLine(i);
            });

            static Func2 t2;

            static void Main(string[] args)
            {
                t2 = delegate(int j)
                {
                    return j;
                };
                t1(2);
                
                Console.WriteLine(t2(1));
                
            }

    新葡亰496net 2

     

    自然在.net 3.0的时候又有了比无名氏函数更方便的东西lambda表达式,那儿就背着了。

    泛型委托
    信托也帮衬泛型的接纳
    泛型委托原型:
    delegate <T1> <委托名><T1,T2,T3...> (T1 t1,T2 t2,T3 t3...)
    例子:
    delegate T2 A<T1,T2>(T1 t);//定义有多个泛型(T1,T2)的嘱托,T2作为委托函数再次回到类型,T1作为委托函数参数类型

    static int test(int t)
    {
          return t;
    }

    static void Main(string[] args)
    {
          A<int, int> a =test;//将泛型委托委托<T1,T2>实例化为<int,int>,即意味着有二个int类型参数且重临类型是int的函数,所以将test用来实例化委托
          Console.WriteLine(a(5));//输出5
    }

    寄托的多播性
    在地点实例化委托的时候来看:必须将叁个相称函数注册到委托上来实例化贰个信托对象,可是一个实例化委托不只好够挂号二个函数还足以登记多少个函数,注册三个函数后,在施行委托的时候会依附登记函数的挂号先后顺序依次实施每叁个挂号函数
    函数注册委托的原型:
    <委托项目> <实例化名> =new <委托项目>(<注册函数>)
    例子:CheckDelegate _checkDelegate=new CheckDelegate(CheckMod);//将函数CheckMod注册到委托实例_checkDelegate上
    在.net 2.0始发能够一向将相配的函数注册到实例化委托:
    <委托项目> <实例化名> =<注册函数>
    例子:CheckDelegate _checkDelegate =CheckMod;//将函数CheckMod注册到委托实例_checkDelegate上
    尔后我们还足以注册三个函数到委托上:
    例子:_checkDelegate =CheckPositive;//将函数CheckPositive注册到委托实例_checkDelegate上
            _checkDelegate();//试行那几个委托实例会先实行CheckMod()再进行CheckPositive()

    实际选择 =符号的时候会咬定
    要是此时托付还尚无实例化(委托实例为null),它会自动用 =侧边的函数实例化委托
    假如此刻嘱托已经实例化,它会只把 =左侧的函数注册到委托实例上
    其余有好几要求注意的是,倘使对注册了函数的嘱托实例从新应用=号赋值,也就是是再度实例化了委托,在此以前在上边注册的函数和委托实例之间也不再爆发任何关系,前边的例证会讲到那一点!

    当然有 =注册函数到委托,也许有-=解除注册
    例子:_checkDelegate-=new CheckDelegate(CheckPositive);//解除CheckPositive对_checkDelegate的注册
            _checkDelegate-=CheckPositive;//.net 2.0始发能够用这种方式消除注册

     

     

    别的当在委托和事件(事件的底细将在末端介绍)上登记了多个函数后,假如委托和事件有重返值,那么调用委托和事件时,返回的将是终极贰个登记函数的重返值。如下示例代码将做详细分解。

    新葡亰496net 3

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace MultiDelegatesReturn
    {
        public delegate int DelMath(int i);//定义委托类DelMath,该委托传入一个int类型参数,返回一个int类型参数
    
        class Program
        {
            static DelMath dMath;//通过委托类型DelMath定义委托实例dMath
            static event DelMath eMath;//通过委托类型DelMath定义事件实例eMath
    
            /// <summary>
            /// 将传入的参数i自加后作为函数返回值
            /// </summary>
            static int IncMath(int i)
            {
                i  ;
                Console.WriteLine("IncMath has been invoked!");
                return i;
            }
    
            /// <summary>
            /// 将传入的参数i自减后作为函数返回值
            /// </summary>
            static int DecMath(int i)
            {
                i--;
                Console.WriteLine("DecMath has been invoked!");
                return i;
            }
    
            static void Main(string[] args)
            {
                int i = 10;//定义int型变量i,初始值为10
    
                dMath  = IncMath;//先将IncMath函数注册到委托实例dMath
                dMath  = DecMath;//再将DecMath函数注册到委托实例dMath
    
                Console.WriteLine("dMath returned:"   dMath(i).ToString());//将int型变量10传入委托实例dMath调用后,返回的结果是9,说明委托实例
                //dMath返回的是后注册的函数DecMath的返回值
    
                eMath  = IncMath;//先将IncMath函数注册到事件实例eMath
                eMath  = DecMath;//再将DecMath函数注册到事件实例eMath
    
                Console.WriteLine("eMath returned:"   eMath(i).ToString());//将int型变量10传入事件实例eMath调用后,返回的结果也是9,说明事件实例
                //eMath返回的也是后注册的函数DecMath的返回值
    
            }
        }
    }
    

    新葡亰496net 4

     

     

     

    c#事件 打听委托随后,就足以来谈谈事件了,C#事件是怎么着?
    c#事件的概念和信托的宣示是如此的貌似:
    event <委托项目> 事件名
    例子:public event CheckDelegate checkEvent;
    地点的例证申明了个事件叫check伊夫nt你会发觉它只比表明委托实例前多了个基本点字event
    宣示了风浪后就可以实例化事件,注册函数到事件,解除事件函数注册其方法和信托的步子完全一样:
    事例:check伊芙nt =new CheckDelegate(CheckMod);//将函数CheckMod注册到事件checkEvent上
           checkEvent =CheckMod;//.net 2.0起来协助这种办法
           checkEvent-=new CheckDelegate(CheckMod);//将函数CheckMod解除对事件check伊芙nt的挂号
           checkEvent-=CheckMod;//.net 2.0初阶协助这种艺术

    从各类迹象都可以看出事件和委托实例是那么的形似,那么为何不直接用委托还要采纳事件呢?其实事件便是对信托的包裹,仿佛同c#类中属性对字段的包装一样,其卷入后得以在信托上包裹更复杂的逻辑,上面大家来看c#中事件的二种评释格局,来打听事件对信托的包装

    隐式注脚事件
    这种情势宣示事件不会细小略,就好似表明委托实例一样:
    event <委托项目> 事件名;
    例子:public event CheckDelegate checkEvent;
    咱俩用反射机制来看看那样评释的事件之中装的终究是何等东西
    新葡亰496net 5
    咱俩得以看出在事件被编写翻译后自动生成了个private的嘱托实例check伊夫nt和七个函数add_checkEvent和remove_check伊夫nt,那多少个函数分别对应事件的 =/-=操作,另外能够看来在表明了平地风波后实在是发出了多少个和事件同名私有的寄托实例checkEvent,对事件的 =/-=操作都会映今后这么些同名委托实例checkEvent上,所以能够在概念事件的类里面一向调用checkEvent()来实施注册函数和对check伊芙nt使用=号重新赋值,实际上这里操作的并非checkEvent事件,而操作的是同名委托实例check伊芙nt,由此隐式表明的事件,其实即是由多个信托实例和七个函数封装而成,全部的操作最后都反映在信托实例上。

    (这里笔者补偿下我的私家了然:事实上在一个类的个中是力不能够支定义三个事变后又定义八个和事件同名的信托实例的,借使您在本例中尝试再定义CheckDelegate check伊芙nt,编写翻译的时候会报错并提示已经定义了名称为checkEvent的嘱托,原因是因为事件本来正是一种新鲜的信托实例(不管是隐式或显式评释的风浪都以那般),由此定义和事件同名的委托实例会报错,所以小编个人以为.net在编写翻译的时候会把隐式表明的风云编写翻译成为委托实例(和事件同名),本例中的check伊夫nt事件在编写翻译后也不再是事件转而被编写翻译成了checkEvent委托实例,不然又怎么恐怕在概念事件的类的里边能够实行事件和对事件赋值呢(这里我们能够看看自家给的显式证明事件的例证,这里面有谈起),独一的解释正是隐式注脚的风云实际正是信托实例)

    显式声明事件
    实在突显注脚事件正是要本身来手动达成隐式申明事件的二个信托实例
    和五个函数:
    event <委托项目> 事件名
    {
          add
          {
                //将函数注册到协调定义的委托实例
          }

          remove
          {
                //解除函数对团结定义的寄托实例的登记
          }
    }

    例子:private CheckDelegate _checkDelete;
            public event CheckDelegate checkEvent
            {
                add
                {
                    _checkDelete = Delegate.Combine(_checkDelete, value) as CheckDelegate;
                }
                remove
                {
                    _checkDelete = Delegate.Remove(_checkDelete, value) as CheckDelegate;
                }
            }
    //Delegate.Combine和Delegate.Remove是.net库函数,功能是统一委托实例注册函数和移除委托实例注册函数并回到合併和移除后的委托实例,具体表明请查阅MSDN

    咱俩再用反射机制查看显式证明事件编写翻译后的代码
    新葡亰496net 6
    可以见到展现注明事件的代码编写翻译后和隐式证明事件的代码几乎同一,只不过这里我们团结定义了事件操作委托实例_checkDelete。另外显式证明的风浪不支持直接调用,尽管在概念事件的类里面也不能够直接调用显式注明的风浪(check伊夫nt();//那样会报错),应该调用事件委托实例(_checkDelete();)。

    本文例子 俗话说得好说得多不及做得多,以往就把例子发出去,例子中还讲了些东西,能够施行例子看了出口结果后再体会:
    率先是个c#类库项目ClassLibrary,里面包蕴三个类分别是显式证明和隐式表明事件
    AutoCheckClass.cs

    新葡亰496net 7

    using System;
    using System.Collections.Generic;
    using System.Text;

    namespace ClassLibrary
    {
        public class AutoCheckClass
        {
            public delegate void CheckDelegate(int number);
            public event CheckDelegate checkEvent;

            public void WriteInner(int n)
            {
                Console.WriteLine(n.ToString());
            }

            public void InitEvent()
            {
                checkEvent = WriteInner;//对事件从新赋值
                //check伊芙nt = new CheckDelegate(WriteInner);//也得以用委托对事件张开赋值
            }

            public void Exec(int n)
            {
                checkEvent(n);
            }

            /*
             接纳这种措施,public event CheckDelegate check伊芙nt;会自动生成一个private CheckDelegate check伊芙nt,
             对于public event CheckDelegate check伊芙nt;的 /-操作都会在编写翻译时反应在private CheckDelegate check伊夫nt上
             并且add/remove .net在编写翻译的时候会自动生成,不用本身再想不开,短处是各样事件的委托都被包裹,无法操作个中间的嘱托
             
             另外接纳这种艺术定义的平地风波,可以在概念事件的类的里边直接对事件开始展览赋值,举个例子能够在Exec函数中增添上边那句代码:
             checkEvent = Exec;
             表示该事件能够被相配的函数或委托赋值早先化。
             何况对事件进行赋值操作,也就是从新开始化事件之中的嘱托(同名委托实例),会让赋值在此以前对事件注册的函数都不再与事件产生关系,具体示例请见本类中Init伊夫nt函数的施用作用。
             */
        }
    }

    新葡亰496net 8

    CheckClass.cs

    新葡亰496net 9

    using System;
    using System.Collections.Generic;
    using System.Text;

    namespace ClassLibrary
    {
        public class CheckClass
        {
            public delegate void CheckDelegate(int number);
            private CheckDelegate _checkDelete;
            public event CheckDelegate checkEvent
            {
                add
                {
                    _checkDelete = Delegate.Combine(_checkDelete, value) as CheckDelegate;
                }
                remove
                {
                    _checkDelete = Delegate.Remove(_checkDelete, value) as CheckDelegate;
                }
            }

            public void Exec(int n)
            {
                _checkDelete(n);
                //checkEvent = Exec;注意展现定义事件的艺术,不协助对事件一向开展赋值
            }

            /*
             delegate在编写翻译的时候会被net编写翻译成贰个类,如下:
             public delegate void CheckDelegate(int number);在编写翻译的时候会编写翻译为上面包车型地铁类
             public sealed class CheckDelegate:System.MulticastDelegate
             {
                public GreetingDelegate(object @object, IntPtr method);
                public virtual IAsyncResult BeginInvoke(string name, AsyncCallback callback, object @object);
                public virtual void EndInvoke(IAsyncResult result);
                public virtual void Invoke(string name);
             }
             而System.MulticastDelegate承继于System.Delegate,所以上边包车型客车代码才会顺遂实施
             _checkDelete = Delegate.Combine(_checkDelete, value) as CheckDelegate;
             _checkDelete = Delegate.Remove(_checkDelete, value) as CheckDelegate; 
             采纳这种艺术可以令你协和钦赐事件的嘱托,乃至足以让两个事件采用同贰个委托,且自身完毕add/remove,能够兑现更头眼昏花的逻辑
             
             其余部必要要注意的是,采取这种办法定义的风浪,纵然在概念事件的类的中间都无能为力对事件直接进行赋值,举例曾在别的种概念格局聊到的在Exec函数中增加:
             checkEvent = Exec;
             会报错:事件“ClassLibrary.CheckClass.check伊芙nt”只好冒出在  = 或 -= 的侧面
             所以在此地我们不应有操作checkEvent,因为它未有同名委托实例,而因该操作_checkDelete
             */
        }
    }

    新葡亰496net 10

    下一场是个调节台项目,须要引进上边的类库的dll文件
    Program.cs

    新葡亰496net 11

    sing System;
    using System.Collections.Generic;
    using System.Text;
    using ClassLibrary;

    namespace DeleGate
    {
        class Temp//定义此类是为了在代码中显得函数对信托和事件的别的一种注册格局
        {
            public delegate void TempDelegate(int u);
            public static TempDelegate td;
            public static event TempDelegate ed;
        }

        class Program
        {
            private static void CheckMod(int number)
            {
                if (number % 2 == 0)
                    Console.WriteLine("输入的是偶数");
                else
                    Console.WriteLine("输入的不是偶数");
            }

            private static void CheckPositive(int number)
            {
                if (number > 0)
                    Console.WriteLine("输入的是正数");
                else
                    Console.WriteLine("输入的不是正数");
            }

            
            static void Main(string[] args)
            {
                CheckClass cc = new CheckClass();
                cc.checkEvent  = new CheckClass.CheckDelegate(CheckMod);
                cc.checkEvent  = new CheckClass.CheckDelegate(CheckPositive);

                AutoCheckClass acc = new AutoCheckClass();
                acc.checkEvent  = new AutoCheckClass.CheckDelegate(CheckMod);
                acc.checkEvent  = new AutoCheckClass.CheckDelegate(CheckPositive);
                //acc.InitEvent();//施行了这几个措施后,由于对事件从新赋了值,上面临事件注册的五个函数都会失灵
                
                Temp.td = CheckMod;//那意味对信托进行赋值(等同于:Temp.td = new Temp.TempDelegate(CheckMod);),和对事件赋值一样,对信托举办赋值相当于伊始化委托,会让赋值从前在信托上注册的函数与信托失去注册涉嫌。
                Temp.td  = CheckPositive;
                Console.WriteLine("Temp的结果");
                Temp.td(50);

                Temp.ed  = CheckMod;
                Temp.ed  = CheckPositive;

                Console.WriteLine("cc的结果");
                cc.Exec(50);
                Console.WriteLine("acc的结果");
                acc.Exec(50);             

                Console.ReadKey();
            }
        }
    }

    新葡亰496net 12

     

     

    叠合更新补充

    调用委托实例的靶子而不是调用委托函数的对象

    通过前边的事例,我们了然到了,委托其实正是C#中的函数指针,有了信托我们得以像使用变量同样来行使函数。可是请牢记调用委托实例的对象,绝不是调用委托函数的目的。这点大家经过如下例子来注脚.

    新葡亰496net 13

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace DelagateInstanceCall
    {
        //DelegateContainer是定义委托类型DelMethod和委托实例delMethod的类
        class DelegateContainer
        {
            public delegate void DelMethod();//定义一个无参数且无返回值的委托类型DelMethod
    
            public DelMethod delMethod;//定义委托类型DelMethod的委托实例delMethod
    
            public int i = 100;//定义一个int类型的变量i在类DelegateContainer之中,赋值100
        }
    
        //MethodDemo是定义委托函数DisplayMethod的类
        class MethodDemo
        {
            protected int i = 200;//定义一个int类型的变量i在类MethodDemo之中,赋值200
    
            //定义委托函数DisplayMethod
            public void DisplayMethod()
            {
                Console.WriteLine("Varible i is : "   this.i.ToString());//显示变量i的值,通过这里的值就可以知道委托函数DisplayMethod的调用对象是谁
            }
        }
    
    
        class Program
        {
            static void Main(string[] args)
            {
                DelegateContainer delCon = new DelegateContainer();//构造类DelegateContainer的对象delCon
                MethodDemo metDemo = new MethodDemo();//构造类MethodDemo的对象metDemo
    
                delCon.delMethod  = metDemo.DisplayMethod;//将函数DisplayMethod注册到委托实例delMethod,让其作为delMethod的委托函数
    
                delCon.delMethod();//调用委托实例delMethod的时候,就会调用在它上注册的委托函数DisplayMethod,那么在执行委托函数DisplayMethod时,其内部代码中的this,到底指的是
                //委托实例delMethod的调用对象delCon呢,还是委托函数DisplayMethod的调用对象metDemo呢?
                //我可以看到这里输出的结果是"Varible i is : 200",说明DisplayMethod内部的this指的是委托函数DisplayMethod本身的调用对象metDemo。这里大家很容易搞混淆,由于我们上面是通过
                //调用委托实例delCon.delMethod来调用委托函数metDemo.DisplayMethod的,看到delCon.delMethod()时大家潜意识可能就会认为由于调用委托实例delMethod的对象是delCon,就认为
                //调用委托实例delMethod上注册函数DisplayMethod的对象也是delCon,其实这是错误的。大家一定要记住委托实例只是一个壳子,它只是用来代表在其上注册的函数,但它并不会改变注册函数
                //的环境变量(比如函数的调用对象等),由于我们上面将委托函数DisplayMethod注册到委托实例delMethod时,使用的是delCon.delMethod  = metDemo.DisplayMethod,所以函数的调用
                //对象始终都是等号右边的对象metDemo,而不会是左边的对象delCon,而调用等号左边的委托实例delCon.delMethod()时,相当于就是在执行等号右边的metDemo.DisplayMethod(),
                //所以委托函数DisplayMethod的调用对象始终是metDemo。
    
                //由此请大家一定要记住,调用委托实例的对象和调用委托函数的对象没有丝毫关系,要看委托函数是谁调用的,还得要看函数注册到委托实例时,等号右边注册函数前的调用对象是谁。
    
                Console.ReadKey();
            }
        }
    }
    

    新葡亰496net 14

    从上边这么些事例,大家得以紧紧记住,调用委托实例的靶子和调用委托函数的对象未有丝毫事关,要看委托函数是何人调用的,还得要看函数注册到委托实例时,等号侧面注册函数前的调用对象是何人。那样在运用委托时就不会出错和弄混淆。

      委托恐怕是C#最难明白的概念之一,不过由于其担任的沉重以及在编制程序中的分布应用,我们只能,认真去切磋。如何工夫够调控委托的定义、掌握其精髓所在呢?笔者在此以前学的时候也比较晕,看着望着就把自个儿给搞糊涂了,一时心烦的就根本放任了。当然认知委托每一个人的主意不一致等,每种人的感触也不平等。以后研究自身要好的感触,希望能给大家有个别帮扶。只是个人见解,只怕不确切,希望各位仁兄研讨指正。
      大家事先使用过抽象类、接口中的抽象方法。这么些对于大家的话,特别的熟知。父类声美赞臣种格局,由子类承接落成。而子类的措施,能够将子类的实例转化为父类的实例实行调用,在后边的接口实例中就有这么的贯彻,你能够看一下。大家得以那样感到,抛开子类、父类,我们就能够说是艺术的存续。仿佛上面例子中的,Perimeter中的ExecuteResult方法承继了接口InterfaceSm的ExecuteResult方法,InterfaceSm中的ExecuteResult就叫做父方法,而Perimeter中的ExecuteResult则改为子方法。

    C#寄托与事件初探

    信托的概念 寄托的宣示原型是 
    delegate <函数重回类型> <委托名> (<函数参数>)
    事例:public delegate void CheckDelegate(int number);//定义了贰个委托CheckDelegate,它能够注册重回void类型且有贰个int作为参数的函数
    如此那般就定义了二个信托,可是委托在.net内一定于注解了贰个类(在背后的代码中会讲到确实那样),类纵然不实例化为指标,相当多效果是从未艺术使用的,委托也是如此.

    新葡亰496net 15新葡亰496net 16Interface Code
    using System;

    作者:Koala''s_Dream 字体:[增加 减小] 类型:转发 时间:二〇一六-02-14 笔者要商量

    信托的实例化 寄托实例化的原型是
    <委托项目> <实例化名>=new <委托项目>(<注册函数>)
    例子:CheckDelegate _checkDelegate=new CheckDelegate(CheckMod);//用函数CheckMod实例化上边的CheckDelegate 委托为_checkDelegate
    在.net 2.0发端能够向来用万分的函数实例化委托:
    <委托项目> <实例化名>=<注册函数>
    例子:CheckDelegate _checkDelegate=CheckMod;//用函数CheckMod实例化上面的CheckDelegate 委托为_checkDelegate
    现行反革命大家就足以像使用函数同样来采纳委托了,在上边的事例中未来实践_checkDelegate()就同样实践CheckMod(),最根本的是现行函数CheckMod也便是位于了变量个中,它能够传递给任何的CheckDelegate引用对象,并且能够当做函数参数字传送递到别的函数内,也足以当作函数的归来类型

    namespace DelegateSo
    {
        /// <summary>
        /// 接口
        /// </summary>
        interface InterfaceSm
        {
            int ExecuteReulst(int x, int y);
        }
        /// <summary>
        /// 总结周长
        /// </summary>
        public class Perimeter : InterfaceSm
        {
            public int ExecuteReulst(int x, int y)
            {
                return 2 * (x   y);
            }
        }
        /// <summary>
        /// 总括面积
        /// </summary>
        public class Area : InterfaceSm
        {
            public int ExecuteReulst(int x, int y)
            {
                return x * y;
            }
        }
        /// <summary>
        /// 操作类
        /// </summary>
        public class Operate
        {
            public static void Main(string[] args)
            {
                int x = 5, y = 10;
                InterfaceSm[] inters ={ new Perimeter(), new Area() };

    事件是信托的一种特别格局,当产生有含义的专门的工作时,事件管理对象公告过程。接下来通过本文给咱们介绍C#信托与事件初探,感兴趣的意中人合伙读书啊

     

                for (int i = 0; i < inters.Length; i )
                {
                    Console.WriteLine("The Result of the Execute is {0}.", inters[i].ExecuteReulst(x, y));
                }
            }
        }
    }
    //output:
    //The Result of the Execute is 30.
    //The Result of the Execute is 50.

    .
    .

    用无名氏函数初阶化委托

     

    寄托给了C#操作函数的灵活性,大家可选用委托像操作变量同样来操作函数,其实那一个意义并不是C#的创始,早在C 时代就有函数指针这一说法,而在作者眼里委托便是C#的函数指针,首先先简要的介绍一下寄托的基本知识:

    地点为了起先化委托要定义一个函数是否感到有一点困苦,其它被予以委托的函数一般皆以通过委托实例来调用,比相当少会一向调用函数自个儿。

      委托是一种援用方法的门类。与信托的签订契约相称(具有同等的参数和重回值)的别样方法都得以分配给该信托。

    委托的定义

    在.net 2.0的时候考虑到这种情形,于是佚名函数就诞生了,由于无名函数没出名字所以一定要用二个委托实例来援用它,定义无名函数正是为了开端化委托

      委托和接口都同意类设计器分离类型评释和兑现。给定的接口可由别的类或结构继续和落实;可感到别的类中的方法创设委托,前提是该措施符合委托的章程具名。接口援引或委托可由不领会实现该接口或委托方法的类的对象使用。

    委托的宣示原型是

    无名函数开始化委托的原型:

      在委托中,大家也足以感到:

    delegate <函数重回类型> <委托名> (<函数参数>)

    <委托项目> <实例化名>=new <委托项目>(delegate(<函数参数>){函数体});

      委托是其余与信托的签字相配的章程的爹爹,全体与寄托具名相配的措施统称为该信托的子方法

    事例:public delegate void CheckDelegate(int number);//定义了三个委托CheckDelegate,它能够挂号重回void类型且有二个int作为参数的函数

    自然在.net 2.0后能够用:

      就好像下边实例所示,ExecuteResult正是全部的与 int MethodName(int x, int y)匹配的不二秘籍的父方法,而getPerimeter和getArea则是ExecuteResult的子方法。  

    如此那般就定义了一个委托,可是委托在.net内一定于表明了叁个类(在后头的代码中会讲到确实如此),类假使不实例化为目的,非常多效果是从未艺术使用的,委托也是如此.

    <委托项目> <实例化名>=delegate(<函数参数>){函数体};

    using System;

    寄托的实例化

    例子:

    namespace DelegateSo
    {
        class Program
        {
            /// <summary>
            /// 委托申明
            /// </summary>
            public delegate int ExecuteResult(int x, int y);
            /// <summary>
            /// 总计矩形周长
            /// </summary>
            /// <param name="x">长</param>
            /// <param name="y">宽</param>
            /// <returns></returns>
            public static int getPerimeter(int x, int y)
            {
                return 2 * (x   y);
            }
            /// <summary>
            /// 计算矩形面积
            /// </summary>
            /// <param name="x">长</param>
            /// <param name="y">宽</param>
            /// <returns></returns>
            public static int getArea(int x, int y)
            {
                return x * y;
            }
            /// <summary>
            /// main
            /// </summary>
            /// <param name="args"></param>
            static void Main(string[] args)
            {
                int x = 5, y = 10;
                ExecuteResult per = getPerimeter;
                ExecuteResult area = getArea;

    委托实例化的原型是

    新葡亰496net 17

                Console.WriteLine("The area of the rectangle is {0}.", area(x, y));

    <委托项目> <实例化名>=new <委托项目>(<注册函数>)

            delegate void Func1(int i);
            delegate int Func2(int i);

                ExecuteResult[] events ={ getPerimeter, getArea };
                for (int i = 0; i < events.Length; i )
                {
                    Console.WriteLine("The Result of Execute is {0}.", events[i](x, y));
                }

    例子:CheckDelegate _checkDelegate=new CheckDelegate(CheckMod);//用函数CheckMod实例化上边的CheckDelegate 委托为_checkDelegate

            static Func1 t1 =new Func1(delegate(int i)
            {
                Console.WriteLine(i);
            });

                //Output
                //The area of the rectangle is 50.
                //The Result of Execute is 30.
                //The Result of Execute is 50.
            }
        }
    }

    在.net 2.0始发能够直接用十分的函数实例化委托:

            static Func2 t2;

     

    <委托项目> <实例化名>=<注册函数>

            static void Main(string[] args)
            {
                t2 = delegate(int j)
                {
                    return j;
                };
                t1(2);
                
                Console.WriteLine(t2(1));
                
            }

      今后应有对信托有个差不离通晓了,那么大家再持续钻探Delegate。

    例子:CheckDelegate _checkDelegate=CheckMod;//用函数CheckMod实例化上边包车型客车CheckDelegate 委托为_checkDelegate
    最近大家就可以像使用函数同样来选拔委托了,在地点的事例中未来推行_checkDelegate()就一律施行CheckMod(),最重要的是今后函数CheckMod也就是位于了变量当中,它能够传递给其他的CheckDelegate引用对象,而且能够看成函数参数字传送递到别的函数内,也足以看作函数的归来类型

    新葡亰496net 18

      委托是一种援用方法的品类。一旦为委托分配了点子,委托将与该形式具备完全同样的作为。委托方法的使用能够像任何任何格局同样,具有参数和重回值.与寄托的签字(由再次回到类型和参数组成)相配的其余格局都足以分配给该信托。那样就能够通过编制程序情势来改造方法调用,还足以向现成类中插入新代码。只要精通委托的签字,便足以分配本人的寄托方法。将艺术作为参数进行援引的技术使委托成为定义回调方法的可以选用。举个例子,能够向排序算法传递对比比较多少个对象的办法的援引。分离相比较代码使得能够运用更通用的点子编写算法。

    事件是信托的一种非常形式,当产生有含义的业务时,事件管理对象通告进程。

     

    寄托的宣示:

    一.C语言中的函数指针

    自然在.net 3.0的时候又有了比佚名函数更方便人民群众的东西lambda表明式,这儿就不说了。

      委托是一种安全地卷入方法的类型,它与 C 和 C 中的函数指针类似。与 C 中的函数指针分裂,委托是面向对象的、类型安全的和保障的。委托的项目由委托的称号定义。如下例中所示。与信托的签署(由再次回到类型和参数组成)相称的任何情势都足以分配给该信托。方法能够是静态方法,也能够是实例方法,例子中并未有反映出来。 

      想要精通什么是寄托,就要先知道函数指针的概念。所谓函数指针,正是指向函数的指针(等于没说-.-)。举例小编定义了三个函数square和cube分别用于计算一个数的平方和立方,小编再定义函数指针calcu,然后笔者让calcu指向square,那么调用calcu时就也就是调用了square函数(注意,此处函数指针接受的参数类型及个数要与函数一致)。很好掌握啊?异常少说,上代码。

    泛型委托
    委托也援救泛型的应用
    泛型委托原型:
    delegate <T1> <委托名><T1,T2,T3...> (T1 t1,T2 t2,T3 t3...)
    例子:
    delegate T2 A<T1,T2>(T1 t);//定义有多个泛型(T1,T2)的寄托,T2作为委托函数重返类型,T1作为委托函数参数类型

     public delegate int ExecuteResult(int x, int y);

    include <stdio.h>

    void square(int x) { printf("square of %d is %dn",x,xx); }
    void cube(int x) { printf("cube of %d is %dn",x,x
    xx); }
    int main()
    {
    void (
    calcu)(int x);
    calcu=square;
    calcu();
    return ;
    }

    二.C#中央委员托的原形

      委托又名委托类型,为啥C#弄出那么些东西?因为C#是一门相比安全的言语,区别意操作指针,于是大家无法定义函数指针。但想要到达一样的意义,于是定义了信托项目。所谓委托项目,其本质正是C中的指针类型。于是代码产生了这般:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    namespace Delegate
    {
    class Program
    {
    static void square(int x) { Console.WriteLine("square of {} is {}", x, x * x); }
    static void cube(int x) { Console.WriteLine("cube of {} is {}", x, x * x * x); }
    delegate void math(int x); //定义委托项目
    static void Main(string[] args)
    {
    math calcu;
    calcu = square;
    calcu();
    Console.ReadKey();
    }
    }
    }

      能够见见,定义委托项目math实际上就也正是概念了void*项目。而委托项目实例化获得的calcu实际上正是函数指针。(说句题外话:定义函数(方法)时要增加static是因为调用函数时未有实例化,只有静态方法可以一直通过类调用)。

    三.信托的使用办法

      大家在上述代码19行背后加上一行代码 calcu =cube; 运营会发掘,square和cube均被调用。能够见到,符号 = 表示绑定方法到委托变量,同理符号 -= 表示裁撤绑定。能够领略为calcu是void **项目,即它指向了二个数组,数组中的各样都以函数指针类型,每趟调用calcu时,遍历此数组,即依次调用每一个绑定的不二等秘书诀。

    四.封装与事件的引进

      下边我们要用面向对象的怀恋将上述代码举行打包,使其变明晰。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    namespace Delegate
    {
    public delegate void math(int x);
    public class Calcu
    {
    public math calcu;
    }
    class Program
    {
    static void square(int x) { Console.WriteLine("square of {} is {}", x, x * x); }
    static void cube(int x) { Console.WriteLine("cube of {} is {}", x, x * x * x); }
    static void Main(string[] args)
    {
    Calcu c = new Calcu();
    c.calcu = square;
    c.calcu = cube;
    c.calcu();
    Console.ReadKey();
    }
    }
    }

    出于委托变量是public的,封装的程度异常低,在外表能够随性所欲修改。为了革新那一个难题,C#引进了风浪。

      所谓事件,实际上照旧委托的实例化,只是其内部多了有个别定义,多了有个别限制。其一,事件实际注脚了二个private类型的嘱托变量,因而在类外非常小概直接调用。

      于是大家将上述代码的第12行改成那样:

    public event math calcu;

      运维之后25行报错了,因为calcu是private的,无法一贯调用。但23,24行并从未报错。那么难题来了,为何我们能够用 =来给calcu绑定方法呢?

      因为那几个,事件还帮大家干了一件工作,正是概念了绑定方法和打消绑定方法的函数,它们是public的,而且将运算符 =,-=重载,和那多个函数对应。

      好了,今后大家要写一个接口函数来实现总结:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    namespace Delegate
    {
    public delegate void math(int x);
    public class Calcu
    {
    public event math calcu;
    public void calculate(int x)
    {
    calcu(x);
    }
    }
    class Program
    {
    static void square(int x) { Console.WriteLine("square of {} is {}", x, x * x); }
    static void cube(int x) { Console.WriteLine("cube of {} is {}", x, x * x * x); }
    static void Main(string[] args)
    {
    Calcu c = new Calcu();
    c.calcu = square;
    c.calcu = cube;
    c.calculate();
    Console.ReadKey();
    }
    }
    }


    详解C#寄托,事件与回调函数

    .Net编制程序中最平日用的因素,事件必然是内部之一。无论在ASP.NET依旧WINFrom开辟中,窗体加载(Load),绘制(Paint),初阶化(Init)等等。
    “protected void Page_Load(object sender, 伊夫ntArgs e)”这段代码相信未有人不熟悉的。留神一点必然会发觉,比比较多的风云措施都是带了“object sender, EventArgs e”那多个参数。那是否和嘱托特别相像呢?

    一、委托(有个别书中也称为委派)

    委托是何等啊?那个名字的意味已经给予了我们想象的半空中,你是编制程序的,你未来正在写贰个ASP.NET网页,而JS是你不熟谙的,于是你委托你的一个人同事来支援你落成JS部分。那便是委托,把您所不能够做的业务交给别的人去做。而怎么明白是哪些人去做啊?当然是要理解名字!而为了差外号字同样的不及人,由此,需求描述叁天个性。

    在C#中,委托的职能是这么描述的:委托就好像多个函数的指针,在程序运转时得以动用它们来调用区别的函数。那个实际上和你委托同事完成JS代码同样。假使有两位同事能够做这件业务,他们要是做的结果可以满足你的急需(就像贰个接口),尽管她们做的经过不等同,何况作出的效果与利益也不相同等,可是,可以达到规定的规范你的供给就可以了。

    1、轻松的嘱托

    那委托要求承载哪些新闻呢?首先,它存款和储蓄了点子名,还应该有参数列表(方法具名),以及重临的类型。举例:
    delegate string/再次来到类型/ ProcessDelegate(int i);
    那就是一个信托的定义。赤褐部分是声称委托的显要字,肉桂色部分是回到的品类,而深藕红部分是委托的门类名,和三个类名大致,而()里的正是参数部分。它的意趣是,你要运用那一个委托来做作业的话,那么,做作业的措施必须满意以下法则:
    1、重临类型和嘱托的归来类型一致,这里是string类型;
    2、能且只好有二个参数,何况是int类型。
    OK,满意上述多个规格,一切就能够干活了:)

    例如:

    using System;
    using System.Collections.Generic;
    using System.Text;

    namespace TestApp
    {
    ///

    /// 委托
    ///
    ///
    ///
    ///
    public delegate string ProcessDelegate(string s1, string s2);

     class Program
     {
         static void Main(string[] args)
         {
             /*  调用方法  */
             ProcessDelegate pd = new ProcessDelegate(new Test().Process);
             Console.WriteLine(pd("Text1", "Text2"));
         }
     }
    
     public class Test
     {
         /// <summary>
         /// 方法
         /// </summary>
         /// <param name="s1"></param>
         /// <param name="s2"></param>
         /// <returns></returns>
         public string Process(string s1,string s2)
         {
             return s1   s2;
         }
     }
    

    }
    输出的结果是:
    Text1Tex2

    2、泛型委托

    泛型的信托,就是然参数的花色不显著,举个例子代码改写为:

    using System;
    using System.Collections.Generic;
    using System.Text;

    namespace TestApp
    {
    ///

    /// 委托
    ///
    ///
    ///
    ///
    public delegate string ProcessDelegate<T,S>(T s1, S s2);

    class Program
    {
        static void Main(string[] args)
        {
            /*  调用方法  */
            ProcessDelegate<string,int> pd = new ProcessDelegate<string,int>(new Test().Process);
            Console.WriteLine(pd("Text1", 100));
        }
    }
    
    public class Test
    {
        /// <summary>
        /// 方法
        /// </summary>
        /// <param name="s1"></param>
        /// <param name="s2"></param>
        /// <returns></returns>
        public string Process(string s1,int s2)
        {
            return s1   s2;
        }
    }
    

    }

    出口的结果正是:
    Text1100

    泛型的事无巨细内容不属于本文的介绍范围,这里不增加说了。

    二、事件

    在某件业务产生时,二个目的足以因而事件通报另四个对象。比如,前台完毕了前台分界面,他照看你,能够把前台和你付出的程序整合了。那正是壹个平地风波。能够看出事件是在二个岁月节点去接触另外一件业务,而除此以外一件事情怎么去做,他不会关心。就事件来讲,关键点正是怎么时候,让什么人去做。

    在C#中,时间概念关键字是event。举例:
    event ProcessDelegate ProcessEvent;

    全部事件定义方法以及施行进度:

    using System;
    using System.Collections.Generic;
    using System.Text;

    namespace TestApp
    {
    ///

    /// 委托
    ///
    ///
    ///
    ///
    public delegate void ProcessDelegate(object sender, EventArgs e);

    class Program
    {
    
    
        static void Main(string[] args)
        {
            /*  第一步执行  */
            Test t = new Test();
            /* 关联事件方法,相当于寻找到了委托人 */
            t.ProcessEvent  = new ProcessDelegate(t_ProcessEvent);
            /* 进入Process方法 */
            Console.WriteLine(t.Process()); 
    
            Console.Read();
        }
    
        static void t_ProcessEvent(object sender, EventArgs e)
        {
            Test t = (Test)sender;
            t.Text1 = "Hello";
            t.Text2 = "World";
        }
    }
    
    public class Test
    {
        private string s1;
    
        public string Text1
        {
            get { return s1; }
            set { s1 = value; }
        }
    
        private string s2;
    
        public string Text2
        {
            get { return s2; }
            set { s2 = value; }
        }
    
    
        public event ProcessDelegate ProcessEvent;
    
        void ProcessAction(object sender, EventArgs e)
        {
            if (ProcessEvent == null)
                ProcessEvent  = new ProcessDelegate(t_ProcessEvent);
            ProcessEvent(sender, e);
        }
    
        //如果没有自己指定关联方法,将会调用该方法抛出错误
        void t_ProcessEvent(object sender, EventArgs e)
        {
            throw new Exception("The method or operation is not implemented.");
        }
    
        void OnProcess()
        {
            ProcessAction(this, EventArgs.Empty);
        }
    
        public string Process()
        {
            OnProcess();
            return s1   s2;
        }
    }
    

    }

    觉获得了何等?是否和代码注入了相当多,相当于是可以用随机符合委托接口(委托确实很像接口)的代码,注入到Process进程。在他回去从前给他赋值。

    三、回调函数

    打了这么多字,好累啊委托和事件。!

    回调函数正是把一个艺术的传给别的贰个情势去实施。在C#有繁多回调函数,譬如异步操作的时候。这里先比方:

    using System;
    using System.Collections.Generic;
    using System.Text;

    namespace TestApp
    {
    ///

    /// 委托
    ///
    ///
    ///
    ///
    public delegate string ProcessDelegate(string s1, string s2);

    class Program
    {
        static void Main(string[] args)
        {
            /*  调用方法  */
            Test t = new Test();
            string r1 = t.Process("Text1", "Text2", new ProcessDelegate(t.Process1));
            string r2 = t.Process("Text1", "Text2", new ProcessDelegate(t.Process2));
            string r3 = t.Process("Text1", "Text2", new ProcessDelegate(t.Process3));
    
            Console.WriteLine(r1);
            Console.WriteLine(r2);
            Console.WriteLine(r3);
        }
    }
    
    public class Test
    {
        public string Process(string s1,string s2,ProcessDelegate process)
        {
            return process(s1, s2);
        }
    
        public string Process1(string s1, string s2)
        {
            return s1   s2;
        }
    
        public string Process2(string s1, string s2)
        {
            return s1   Environment.NewLine   s2;
        }
    
        public string Process3(string s1, string s2)
        {
            return s2   s1;
        }
    }
    

    }

    输出结果:
    Text1Text2
    Text1
    Text2
    Text2Text1

    Process方法调用了四个回调函数,当然这里只实行了回调函数。能够看来,能够把自由二个顺应那一个委托的点子传递进入,意思便是说那有的代码是可变的。而规划上有一个抽离出可变部分代码的尺码,这种用法无疑能够用到这种场地了。


    寄托给了C#操作函数的灵活性,大家可选取委托像操作变量同样来操作函数,其实这么些职能而不是C#的创始,早在C 时代就有函数指针这一说法,而以小编之见委托正是C#的函数指针,首先先简要的牵线一下寄托的基本知识:

    信托的概念
    委托的宣示原型是
    delegate <函数重回类型> <委托名> (<函数参数>)
    事例:public delegate void CheckDelegate(int number);//定义了一个委托CheckDelegate,它能够挂号再次回到void类型且有贰个int作为参数的函数
    如此那般就定义了贰个信托,不过委托在.net内一定于评释了贰个类(在后边的代码中会讲到确实那样),类要是不实例化为指标,相当多效应是从未艺术使用的,委托也是如此.

    信托的实例化
    委托实例化的原型是
    <委托项目> <实例化名>=new <委托项目>(<注册函数>)
    例子:CheckDelegate _checkDelegate=new CheckDelegate(CheckMod);//用函数CheckMod实例化上边的CheckDelegate 委托为_checkDelegate
    在.net 2.0开首能够直接用特别的函数实例化委托:
    <委托项目> <实例化名>=<注册函数>
    例子:CheckDelegate _checkDelegate=CheckMod;//用函数CheckMod实例化下面包车型大巴CheckDelegate 委托为_checkDelegate
    今昔大家就能够像使用函数同样来利用委托了,在下边的例子中今后进行_checkDelegate()就同样实行CheckMod(),最重大的是现行反革命函数CheckMod相当于位于了变量其中,它能够传递给其余的CheckDelegate援用对象,而且能够用作函数参数传递到其余函数内,也可以视作函数的回来类型

    用无名氏函数开端化委托

    地方为了伊始化委托要定义一个函数是或不是认为有个别麻烦,其余被予以委托的函数一般都以由此信托实例来调用,非常少会直接调用函数自个儿。

    在.net 2.0的时候考虑到这种场所,于是无名氏函数就出生了,由于佚名函数未有名字所以必须要用三个寄托实例来引用它,定义佚名函数正是为了起始化委托

    无名氏函数发轫化委托的原型:

    <委托项目> <实例化名>=new <委托项目>(delegate(<函数参数>){函数体});

    自然在.net 2.0后能够用:

    <委托项目> <实例化名>=delegate(<函数参数>){函数体};

    例子:

        delegate void Func1(int i);
        delegate int Func2(int i);
    
        static Func1 t1 =new Func1(delegate(int i)
        {
            Console.WriteLine(i);
        });
    
        static Func2 t2;
    
        static void Main(string[] args)
        {
            t2 = delegate(int j)
            {
                return j;
            };
            t1(2);
    
            Console.WriteLine(t2(1));
    
        }
    

    当然在.net 3.0的时候又有了比无名函数更便于的东西lambda表明式,这儿就不说了。

    泛型委托
    委托也支撑泛型的行使
    泛型委托原型:
    delegate

    static int test(int t)
    {
    return t;
    }

    static void Main(string[] args)
    {
    A<int, int> a =test;//将泛型委托委托<T1,T2>实例化为<int,int>,即意味着有多个int类型参数且重临类型是int的函数,所以将test用来实例化委托
    Console.WriteLine(a(5));//输出5
    }

    委托的多播性
    在上面实例化委托的时候来看:必须将叁个相配函数注册到委托上来实例化二个寄托对象,可是三个实例化委托不仅可以够登记叁个函数还是能注册八个函数,注册多个函数后,在实行委托的时候会基于登记函数的登记先后顺序依次推行每三个挂号函数
    函数注册委托的原型:
    <委托项目> <实例化名> =new <委托项目>(<注册函数>)
    例子:CheckDelegate _checkDelegate=new CheckDelegate(CheckMod);//将函数CheckMod注册到委托实例_checkDelegate上
    在.net 2.0从头能够直接将非凡的函数注册到实例化委托:
    <委托项目> <实例化名> =<注册函数>
    例子:CheckDelegate _checkDelegate =CheckMod;//将函数CheckMod注册到委托实例_checkDelegate上
    未来我们还足以挂号多少个函数到委托上:
    例子:_checkDelegate =CheckPositive;//将函数CheckPositive注册到委托实例_checkDelegate上
    _checkDelegate();//实行这几个委托实例会西子行CheckMod()再实施CheckPositive()

    实际选取 =符号的时候会判断
    万一此刻嘱托还从来不实例化(委托实例为null),它会自行用 =左边的函数实例化委托
    假如此刻托付已经实例化,它会只把 =左边的函数注册到委托实例上
    除此以外有几许内需留意的是,假如对登记了函数的信托实例从新利用=号赋值,也就是是再次实例化了信托,以前在地方注册的函数和委托实例之间也不再爆发其余涉及,前边的例子会讲到那点!

    自然有 =注册函数到委托,也是有-=解除注册
    例子:_checkDelegate-=new CheckDelegate(CheckPositive);//解除CheckPositive对_checkDelegate的注册
    _checkDelegate-=CheckPositive;//.net 2.0从头能够用这种办法消除注册

    其余当在信托和事件(事件的内部原因将要后面介绍)上登记了八个函数后,借使委托和事件有重临值,那么调用委托和事件时,重回的将是最终多个注册函数的重临值。如下示例代码将做详细表达。

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

    namespace MultiDelegatesReturn
    {
    public delegate int DelMath(int i);//定义委托类DelMath,该信托传入八个int类型参数,再次来到二个int类型参数

    class Program
    {
        static DelMath dMath;//通过委托类型DelMath定义委托实例dMath
        static event DelMath eMath;//通过委托类型DelMath定义事件实例eMath
    
        /// <summary>
        /// 将传入的参数i自加后作为函数返回值
        /// </summary>
        static int IncMath(int i)
        {
            i  ;
            Console.WriteLine("IncMath has been invoked!");
            return i;
        }
    
        /// <summary>
        /// 将传入的参数i自减后作为函数返回值
        /// </summary>
        static int DecMath(int i)
        {
            i--;
            Console.WriteLine("DecMath has been invoked!");
            return i;
        }
    
        static void Main(string[] args)
        {
            int i = 10;//定义int型变量i,初始值为10
    
            dMath  = IncMath;//先将IncMath函数注册到委托实例dMath
            dMath  = DecMath;//再将DecMath函数注册到委托实例dMath
    
            Console.WriteLine("dMath returned:"   dMath(i).ToString());//将int型变量10传入委托实例dMath调用后,返回的结果是9,说明委托实例
            //dMath返回的是后注册的函数DecMath的返回值
    
            eMath  = IncMath;//先将IncMath函数注册到事件实例eMath
            eMath  = DecMath;//再将DecMath函数注册到事件实例eMath
    
            Console.WriteLine("eMath returned:"   eMath(i).ToString());//将int型变量10传入事件实例eMath调用后,返回的结果也是9,说明事件实例
            //eMath返回的也是后注册的函数DecMath的返回值
    
        }
    }
    

    }

    c#事件:
    驾驭委托随后,就能够来斟酌事件了,C#事件是何许?
    c#事件的概念和寄托的宣示是这般的相似:
    event <委托项目> 事件名
    例子:public event CheckDelegate checkEvent;
    上边的事例表明了个事件叫checkEvent你会开采它只比申明委托实例前多了个主要字event
    证明了平地风波后就能够实例化事件,注册函数到事件,解除事件函数注册其艺术和委托的步骤一模一样:
    事例:checkEvent =new CheckDelegate(CheckMod);//将函数CheckMod注册到事件check伊夫nt上
    checkEvent =CheckMod;//.net 2.0上马辅助这种艺术
    check伊夫nt-=new CheckDelegate(CheckMod);//将函数CheckMod解除对事件checkEvent的挂号
    check伊芙nt-=CheckMod;//.net 2.0开端协助这种情势

    从种种迹象都能够看来事件和嘱托实例是那么的貌似,那么为何不直接用委托还要选取事件吧?其实事件正是对信托的包裹,就好像同c#类中属性对字段的包裹同样,其包装后得以在委托上包裹更目不暇接的逻辑,上边大家来看c#中事件的二种评释格局,来打探事件对信托的包裹

    隐式注脚事件
    这种方式宣示事件异常的粗略,就好似注解委托实例一样:
    event <委托项目> 事件名;
    例子:public event CheckDelegate checkEvent;
    咱俩用反射机制来拜望那样注明的平地风波之中装的到底是如张忠西

    大家能够看到在事件被编写翻译后自动生成了个private的嘱托实例checkEvent和八个函数add_checkEvent和remove_check伊夫nt,那八个函数分别对应事件的 =/-=操作,别的可以见见在宣称了风浪后实在是发出了贰个和事件同名私有的寄托实例check伊芙nt,对事件的 =/-=操作都会显示在那些同名委托实例checkEvent上,所以能够在概念事件的类里面一向调用check伊夫nt()来进行注册函数和对checkEvent使用=号重新赋值,实际上这里操作的并不是checkEvent事件,而操作的是同名委托实例checkEvent,由此隐式注明的事件,其实便是由一个委托实例和五个函数封装而成,全部的操作最后都映今后委托实例上。

    (这里笔者补偿下自家的私人民居房领悟:事实上在贰个类的中间是望眼欲穿定义二个事变后又定义二个和事件同名的信托实例的,假若您在本例中尝试再定义CheckDelegate check伊芙nt,编写翻译的时候会报错并提示已经定义了堪称check伊夫nt的嘱托,原因是因为事件本来便是一种特其他信托实例(不管是隐式或显式注明的风云都是那样),因而定义和事件同名的嘱托实例会报错,所以自身个人感觉.net在编译的时候会把隐式注解的风云编写翻译成为委托实例(和事件同名),本例中的check伊夫nt事件在编写翻译后也不再是事件转而被编写翻译成了checkEvent委托实例,不然又怎么只怕在概念事件的类的内部能够施行事件和对事件赋值呢(这里大家能够看看本人给的显式注脚事件的例子,这里边有提起),独一的解释正是隐式证明的事件其实正是委托实例)

    显式注明事件
    事实上显示证明事件就是要自身来手动完毕隐式评释事件的贰个委托实例
    和四个函数:
    event <委托项目> 事件名
    {
    add
    {
    //将函数注册到温馨定义的寄托实例
    }

      remove
      {
            //解除函数对自己定义的委托实例的注册
      }
    

    }

    例子:private CheckDelegate _checkDelete;
    public event CheckDelegate checkEvent
    {
    add
    {
    _checkDelete = Delegate.Combine(_checkDelete, value) as CheckDelegate;
    }
    新葡亰496net,remove
    {
    _checkDelete = Delegate.Remove(_checkDelete, value) as CheckDelegate;
    }
    }
    //Delegate.Combine和Delegate.Remove是.net库函数,功能是联合委托实例注册函数和移除委托实例注册函数并再次来到合併和移除后的委托实例,具体表明请查阅MSDN

    大家再用反射机制查看显式注明事件编写翻译后的代码

    能够见见显示声明事件的代码编写翻译后和隐式注脚事件的代码大致同样,只可是这里我们友好定义了风浪操作委托实例_checkDelete。别的显式注解的事件不援助直接调用,纵然在概念事件的类里面也不可能直接调用显式注明的平地风波(checkEvent();//那样会报错),应该调用事件委托实例(_checkDelete();)。

    正文例子
    俗话说得好说得多不比做得多,以后就把例子发出去,例子中还讲了些东西,能够推行例子看了出口结果后再体会:
    率先是个c#类库项目ClassLibrary,里面含有五个类分别是显式证明和隐式表明事件
    AutoCheckClass.cs

    using System;
    using System.Collections.Generic;
    using System.Text;

    namespace ClassLibrary
    {
    public class AutoCheckClass
    {
    public delegate void CheckDelegate(int number);
    public event CheckDelegate checkEvent;

        public void WriteInner(int n)
        {
            Console.WriteLine(n.ToString());
        }
    
        public void InitEvent()
        {
            checkEvent = WriteInner;//对事件从新赋值
            //checkEvent = new CheckDelegate(WriteInner);//也可以用委托对事件进行赋值
        }
    
        public void Exec(int n)
        {
            checkEvent(n);
        }
    
        /*
         采用这种方式,public event CheckDelegate checkEvent;会自动生成一个private CheckDelegate checkEvent,
         对于public event CheckDelegate checkEvent;的 /-操作都会在编译时反应在private CheckDelegate checkEvent上
         而且add/remove .net在编译的时候会自动生成,不用自己再操心,缺点是每个事件的委托都被封装,无法操作其内部的委托
    
         此外采用这种方式定义的事件,可以在定义事件的类的内部直接对事件进行赋值,例如可以在Exec函数中加上下面这句代码:
         checkEvent = Exec;
         表示该事件可以被匹配的函数或委托赋值初始化。
         并且对事件进行赋值操作,相当于从新初始化事件内部的委托(同名委托实例),会让赋值之前对事件注册的函数都不再与事件产生关系,具体示例请见本类中InitEvent函数的使用效果。
         */
    }
    

    }

    CheckClass.cs

    using System;
    using System.Collections.Generic;
    using System.Text;

    namespace ClassLibrary
    {
    public class CheckClass
    {
    public delegate void CheckDelegate(int number);
    private CheckDelegate _checkDelete;
    public event CheckDelegate checkEvent
    {
    add
    {
    _checkDelete = Delegate.Combine(_checkDelete, value) as CheckDelegate;
    }
    remove
    {
    _checkDelete = Delegate.Remove(_checkDelete, value) as CheckDelegate;
    }
    }

        public void Exec(int n)
        {
            _checkDelete(n);
            //checkEvent = Exec;注意显示定义事件的方式,不支持对事件直接进行赋值
        }
    
        /*
         delegate在编译的时候会被net编译成一个类,如下:
         public delegate void CheckDelegate(int number);在编译的时候会编译为下面的类
         public sealed class CheckDelegate:System.MulticastDelegate
         {
            public GreetingDelegate(object @object, IntPtr method);
            public virtual IAsyncResult BeginInvoke(string name, AsyncCallback callback, object @object);
            public virtual void EndInvoke(IAsyncResult result);
            public virtual void Invoke(string name);
         }
         而System.MulticastDelegate继承于System.Delegate,所以下面的代码才会顺利执行
         _checkDelete = Delegate.Combine(_checkDelete, value) as CheckDelegate;
         _checkDelete = Delegate.Remove(_checkDelete, value) as CheckDelegate; 
         采用这种方法可以让你自己指定事件的委托,甚至可以让多个事件使用同一个委托,且自己实现add/remove,可以实现更复杂的逻辑
    
         此外需要注意的是,采用这种方式定义的事件,就算在定义事件的类的内部都无法对事件直接进行赋值,例如先前在另外种定义方式说到的在Exec函数中加上:
         checkEvent = Exec;
         会报错:事件“ClassLibrary.CheckClass.checkEvent”只能出现在  = 或 -= 的左边
         所以在这里我们不应该操作checkEvent,因为它没有同名委托实例,而因该操作_checkDelete
         */
    }
    

    }

    然后是个调整台项目,要求引进上面包车型客车类库的dll文件
    Program.cs

    sing System;
    using System.Collections.Generic;
    using System.Text;
    using ClassLibrary;

    namespace DeleGate
    {
    class Temp//定义此类是为着在代码中呈现函数对信托和事件的别的一种注册格局
    {
    public delegate void TempDelegate(int u);
    public static TempDelegate td;
    public static event TempDelegate ed;
    }

    class Program
    {
        private static void CheckMod(int number)
        {
            if (number % 2 == 0)
                Console.WriteLine("输入的是偶数");
            else
                Console.WriteLine("输入的不是偶数");
        }
    
        private static void CheckPositive(int number)
        {
            if (number > 0)
                Console.WriteLine("输入的是正数");
            else
                Console.WriteLine("输入的不是正数");
        }
    
    
        static void Main(string[] args)
        {
            CheckClass cc = new CheckClass();
            cc.checkEvent  = new CheckClass.CheckDelegate(CheckMod);
            cc.checkEvent  = new CheckClass.CheckDelegate(CheckPositive);
    
            AutoCheckClass acc = new AutoCheckClass();
            acc.checkEvent  = new AutoCheckClass.CheckDelegate(CheckMod);
            acc.checkEvent  = new AutoCheckClass.CheckDelegate(CheckPositive);
            //acc.InitEvent();//执行了这个方法后,由于对事件从新赋了值,上面对事件注册的两个函数都会失效
    
            Temp.td = CheckMod;//这表示对委托进行赋值(等同于:Temp.td = new Temp.TempDelegate(CheckMod);),和对事件赋值一样,对委托进行赋值相当于初始化委托,会让赋值之前在委托上注册的函数与委托失去注册关系。
            Temp.td  = CheckPositive;
            Console.WriteLine("Temp的结果");
            Temp.td(50);
    
            Temp.ed  = CheckMod;
            Temp.ed  = CheckPositive;
    
            Console.WriteLine("cc的结果");
            cc.Exec(50);
            Console.WriteLine("acc的结果");
            acc.Exec(50);
    
    
            Console.ReadKey();
        }
    }
    

    }

    外加更新补充

    调用委托实例的靶子实际不是调用委托函数的对象

    通过前面包车型的士事例,大家领会到了,委托其实便是C#中的函数指针,有了寄托大家得以像使用变量一样来行使函数。不过请记住调用委托实例的指标,绝不是调用委托函数的靶子。那一点大家经过如下例子来证明.

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

    namespace DelagateInstanceCall
    {
    //DelegateContainer是概念委托项目DelMethod和委托实例delMethod的类
    class DelegateContainer
    {
    public delegate void DelMethod();//定义三个无参数且无返回值的委托项目DelMethod

        public DelMethod delMethod;//定义委托类型DelMethod的委托实例delMethod
    
        public int i = 100;//定义一个int类型的变量i在类DelegateContainer之中,赋值100
    }
    
    //MethodDemo是定义委托函数DisplayMethod的类
    class MethodDemo
    {
        protected int i = 200;//定义一个int类型的变量i在类MethodDemo之中,赋值200
    
        //定义委托函数DisplayMethod
        public void DisplayMethod()
        {
            Console.WriteLine("Varible i is : "   this.i.ToString());//显示变量i的值,通过这里的值就可以知道委托函数DisplayMethod的调用对象是谁
        }
    }
    
    
    class Program
    {
        static void Main(string[] args)
        {
            DelegateContainer delCon = new DelegateContainer();//构造类DelegateContainer的对象delCon
            MethodDemo metDemo = new MethodDemo();//构造类MethodDemo的对象metDemo
    
            delCon.delMethod  = metDemo.DisplayMethod;//将函数DisplayMethod注册到委托实例delMethod,让其作为delMethod的委托函数
    
            delCon.delMethod();//调用委托实例delMethod的时候,就会调用在它上注册的委托函数DisplayMethod,那么在执行委托函数DisplayMethod时,其内部代码中的this,到底指的是
            //委托实例delMethod的调用对象delCon呢,还是委托函数DisplayMethod的调用对象metDemo呢?
            //我可以看到这里输出的结果是"Varible i is : 200",说明DisplayMethod内部的this指的是委托函数DisplayMethod本身的调用对象metDemo。这里大家很容易搞混淆,由于我们上面是通过
            //调用委托实例delCon.delMethod来调用委托函数metDemo.DisplayMethod的,看到delCon.delMethod()时大家潜意识可能就会认为由于调用委托实例delMethod的对象是delCon,就认为
            //调用委托实例delMethod上注册函数DisplayMethod的对象也是delCon,其实这是错误的。大家一定要记住委托实例只是一个壳子,它只是用来代表在其上注册的函数,但它并不会改变注册函数
            //的环境变量(比如函数的调用对象等),由于我们上面将委托函数DisplayMethod注册到委托实例delMethod时,使用的是delCon.delMethod  = metDemo.DisplayMethod,所以函数的调用
            //对象始终都是等号右边的对象metDemo,而不会是左边的对象delCon,而调用等号左边的委托实例delCon.delMethod()时,相当于就是在执行等号右边的metDemo.DisplayMethod(),
            //所以委托函数DisplayMethod的调用对象始终是metDemo。
    
            //由此请大家一定要记住,调用委托实例的对象和调用委托函数的对象没有丝毫关系,要看委托函数是谁调用的,还得要看函数注册到委托实例时,等号右边注册函数前的调用对象是谁。
    
            Console.ReadKey();
        }
    }
    

    }

    从地点这么些事例,我们能够牢牢记住,调用委托实例的靶子和调用委托函数的对象未有丝毫涉及,要看委托函数是什么人调用的,还得要看函数注册到委托实例时,等号左边注册函数前的调用对象是何人。那样在采用委托时就不会出错搅拌混淆。

    static int test(int t)
    {
          return t;
    }

     

    static void Main(string[] args)
    {
          A<int, int> a =test;//将泛型委托委托<T1,T2>实例化为<int,int>,即意味着有二个int类型参数且重回类型是int的函数,所以将test用来实例化委托
          Console.WriteLine(a(5));//输出5
    }

    public static int getPerimeter(int x, int y){新葡亰496net 19}

    委托的多播性
    在上头实例化委托的时候看看:必须将贰个相配函数注册到委托上来实例化三个寄托对象,但是叁个实例化委托不仅可以够登记贰个函数还是能够注册八个函数,注册多个函数后,在实行委托的时候会基于登记函数的登记先后顺序依次实施每个注册函数
    函数注册委托的原型:
    <委托项目> <实例化名> =new <委托项目>(<注册函数>)
    例子:CheckDelegate _checkDelegate=new CheckDelegate(CheckMod);//将函数CheckMod注册到委托实例_checkDelegate上
    在.net 2.0早先能够直接将极度的函数注册到实例化委托:
    <委托项目> <实例化名> =<注册函数>
    例子:CheckDelegate _checkDelegate =CheckMod;//将函数CheckMod注册到委托实例_checkDelegate上
    其后大家还足以登记四个函数到委托上:
    例子:_checkDelegate =CheckPositive;//将函数CheckPositive注册到委托实例_checkDelegate上
            _checkDelegate();//执行这几个委托实例会先推行CheckMod()再实行CheckPositive()

     

    骨子里利用 =符号的时候会咬定
    一旦那时候托付还不曾实例化(委托实例为null),它会自动用 =左边的函数实例化委托
    如若此时委托已经实例化,它会只把 =侧边的函数注册到委托实例上
    另外有一点点供给留神的是,如若对注册了函数的信托实例从新应用=号赋值,相当于是再度实例化了委托,以前在下面注册的函数和委托实例之间也不再产生任何关系,后边的事例会讲到那一点!

    public static int getArea(int x, int y){新葡亰496net 20}

    自然有 =注册函数到委托,也许有-=解除注册
    例子:_checkDelegate-=new CheckDelegate(CheckPositive);//解除CheckPositive对_checkDelegate的注册
            _checkDelegate-=CheckPositive;//.net 2.0从头能够用这种情势消除注册

     

     

     委托的特色:

     

      1、委托类似于 C 函数指针,但它是项目安全的

    另外当在信托和事件(事件的内部情形就要前边介绍)上登记了几个函数后,假设委托和事件有重临值,那么调用委托和事件时,重临的将是最终二个登记函数的重临值。如下示例代码将做详细表明。

      2、委托允许将艺术作为参数实行传递。

    新葡亰496net 21

      3、委托可用以定义回调方法。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace MultiDelegatesReturn
    {
        public delegate int DelMath(int i);//定义委托类DelMath,该委托传入一个int类型参数,返回一个int类型参数
    
        class Program
        {
            static DelMath dMath;//通过委托类型DelMath定义委托实例dMath
            static event DelMath eMath;//通过委托类型DelMath定义事件实例eMath
    
            /// <summary>
            /// 将传入的参数i自加后作为函数返回值
            /// </summary>
            static int IncMath(int i)
            {
                i  ;
                Console.WriteLine("IncMath has been invoked!");
                return i;
            }
    
            /// <summary>
            /// 将传入的参数i自减后作为函数返回值
            /// </summary>
            static int DecMath(int i)
            {
                i--;
                Console.WriteLine("DecMath has been invoked!");
                return i;
            }
    
            static void Main(string[] args)
            {
                int i = 10;//定义int型变量i,初始值为10
    
                dMath  = IncMath;//先将IncMath函数注册到委托实例dMath
                dMath  = DecMath;//再将DecMath函数注册到委托实例dMath
    
                Console.WriteLine("dMath returned:"   dMath(i).ToString());//将int型变量10传入委托实例dMath调用后,返回的结果是9,说明委托实例
                //dMath返回的是后注册的函数DecMath的返回值
    
                eMath  = IncMath;//先将IncMath函数注册到事件实例eMath
                eMath  = DecMath;//再将DecMath函数注册到事件实例eMath
    
                Console.WriteLine("eMath returned:"   eMath(i).ToString());//将int型变量10传入事件实例eMath调用后,返回的结果也是9,说明事件实例
                //eMath返回的也是后注册的函数DecMath的返回值
    
            }
        }
    }
    

      4、委托能够链接在一起;举例,能够对三个风云调用三个点子。

    新葡亰496net 22

      5、方法无需与信托签字正确匹配。有关越来越多信息,请参见协变和逆变。

     

      6、C# 2.0 版引入了佚名格局的概念,此类措施允许将代码块作为参数字传送递,以替代单独定义的格局。

     

    常用的办法:

     

      1、合并委托(多路广播委托)

    c#事件 叩问委托随后,就可以来研讨事件了,C#事件是何许?
    c#事件的定义和委托的扬言是这么的形似:
    event <委托项目> 事件名
    例子:public event CheckDelegate checkEvent;
    上边的事例评释了个事件叫check伊夫nt你会发掘它只比评释委托实例前多了个珍视字event
    宣示了平地风波后就足以实例化事件,注册函数到事件,解除事件函数注册其艺术和嘱托的步调大同小异:
    事例:checkEvent =new CheckDelegate(CheckMod);//将函数CheckMod注册到事件check伊夫nt上
           check伊夫nt =CheckMod;//.net 2.0开首帮衬这种措施
           checkEvent-=new CheckDelegate(CheckMod);//将函数CheckMod解除对事件check伊夫nt的登记
           checkEvent-=CheckMod;//.net 2.0开首辅助这种艺术

      委托对象的贰个用场在于,能够应用 运算符将它们分配给一个要变为多路广播委托的寄托实例。组合的委托可调用组成它的那多少个委托。唯有一样类其余寄托才方可结合。- 运算符可用来从构成的委托移除组件委托。以为就如做小学数学一样,轻便、火速。

    从各样迹象都得以看到事件和信托实例是那么的一般,那么为啥不直接用委托还要选取事件呢?其实事件正是对信托的包装,就好像同c#类中属性对字段的卷入同样,其卷入后方可在信托上包裹更复杂的逻辑,上面大家来看c#中事件的三种声明格局,来询问事件对信托的卷入

    在上述Main方法中加入如下代码:

    隐式注明事件
    这种措施宣示事件很轻松,就好像同注脚委托实例同样:
    event <委托项目> 事件名;
    例子:public event CheckDelegate checkEvent;
    大家用反射机制来寻访那样注脚的风浪之中装的到底是什么样事物
    新葡亰496net 23
    大家得以见见在事变被编写翻译后自动生成了个private的信托实例check伊夫nt和多个函数add_checkEvent和remove_checkEvent,那多少个函数分别对应事件的 =/-=操作,别的能够看出在表明了事件后当真是产生了贰个和事件同名私有的嘱托实例check伊芙nt,对事件的 =/-=操作都会呈现在这么些同名委托实例checkEvent上,所以能够在概念事件的类里面从来调用check伊芙nt()来进行注册函数和对checkEvent使用=号重新赋值,实际上这里操作的并非checkEvent事件,而操作的是同名委托实例check伊夫nt,由此隐式注解的平地风波,其实正是由一个委托实例和多少个函数封装而成,全体的操作最后都反映在信托实例上。

                //加,假如有重临值,则赶回最终四个试行函数的重回值
                ExecuteResult operates = per   area;
                Console.WriteLine("The Result of Execute is {0}.", operates(x, y));
                //Output
                //The Result of Execute is 50.

    (这里作者补偿下本人的私有知道:事实上在二个类的内部是心有余而力不足定义二个事件后又定义多少个和事件同名的嘱托实例的,如果您在本例中品尝再定义CheckDelegate checkEvent,编写翻译的时候会报错并提示已经定义了名称为check伊芙nt的寄托,原因是因为事件本来正是一种万分的嘱托实例(不管是隐式或显式注解的平地风波都以如此),由此定义和事件同名的寄托实例会报错,所以自个儿个人认为.net在编写翻译的时候会把隐式申明的平地风波编写翻译成为委托实例(和事件同名),本例中的check伊芙nt事件在编写翻译后也不再是事件转而被编写翻译成了check伊芙nt委托实例,不然又怎么可能在概念事件的类的中间能够试行事件和对事件赋值呢(这里大家能够看看自家给的显式证明事件的例证,这里面有聊到),独一的表达就是隐式注解的风浪实际就是信托实例)

                //减
                ExecuteResult operate_del = operates - area;
                Console.WriteLine("The Per result is {0}.", operate_del(x, y));
                //Output
                //The Per result is 30.

    显式注解事件
    实质上突显评释事件就是要团结来手动完结隐式注脚事件的二个信托实例
    和多个函数:
    event <委托项目> 事件名
    {
          add
          {
                //将函数注册到自身定义的信托实例
          }

     

          remove
          {
                //解除函数对友好定义的嘱托实例的登记
          }
    }

      2、GetInvocationList重临委托的调用列表 

    例子:private CheckDelegate _checkDelete;
            public event CheckDelegate checkEvent
            {
                add
                {
                    _checkDelete = Delegate.Combine(_checkDelete, value) as CheckDelegate;
                }
                remove
                {
                    _checkDelete = Delegate.Remove(_checkDelete, value) as CheckDelegate;
                }
            }
    //Delegate.Combine和Delegate.Remove是.net库函数,成效是联合委托实例注册函数和移除委托实例注册函数并赶回合併和移除后的嘱托实例,具体表达请查阅MSDN

    新葡亰496net 24新葡亰496net 25GetInvocationList()
                //得到委托中的方法总的数量
                int count = operates.GetInvocationList().GetLength(0);//operates = per   area;
                Console.WriteLine("{0}", count);
                //遍历委托中具有的点子
                foreach (ExecuteResult item in operates.GetInvocationList())
                {
                    Console.WriteLine("The Result is {0}.", item(x, y));
                }
                //Output
                //2
                //The Result is 30.
                //The Result is 50.

    作者们再用反射机制查看显式注解事件编写翻译后的代码
    新葡亰496net 26
    能够看看展现评释事件的代码编写翻译后和隐式表明事件的代码大概同一,只可是这里我们和煦定义了事件操作委托实例_checkDelete。别的显式注明的平地风波不协理直接调用,固然在概念事件的类里面也不可能一向调用显式注解的风云(checkEvent();//那样会报错),应该调用事件委托实例(_checkDelete();)。

     

    正文例子 俗话说得好说得多不及做得多,以往就把例子发出去,例子中还讲了些东西,能够施行例子看了出口结果后再体会:
    首先是个c#类库项目ClassLibrary,里面包罗多个类分别是显式表明和隐式注脚事件
    AutoCheckClass.cs

    分布的嘱托实例

    新葡亰496net 27

      1、定期施行,TimerCallback 

    using System;
    using System.Collections.Generic;
    using System.Text;

    [ComVisible(true)]
    public delegate void TimerCallback(object state);

    namespace ClassLibrary
    {
        public class AutoCheckClass
        {
            public delegate void CheckDelegate(int number);
            public event CheckDelegate checkEvent;

     

            public void WriteInner(int n)
            {
                Console.WriteLine(n.ToString());
            }

    Timer iTimer = new Timer(new TimerCallback(Doing));//定期进行
    iTimer.Change(TimeSpan.FromSeconds(5), TimeSpan.FromMinutes(1));

            public void InitEvent()
            {
                checkEvent = WriteInner;//对事件从新赋值
                //checkEvent = new CheckDelegate(WriteInner);//也足以用委托对事件进展赋值
            }

    public void Doing(Object nObject){新葡亰496net 28}

            public void Exec(int n)
            {
                checkEvent(n);
            }

      2、自定义控件

            /*
             采纳这种艺术,public event CheckDelegate check伊夫nt;会自动生成三个private CheckDelegate checkEvent,
             对于public event CheckDelegate checkEvent;的 /-操作都会在编写翻译时反应在private CheckDelegate checkEvent上
             并且add/remove .net在编译的时候会自动生成,不用自个儿再想不开,缺点是各种事件的委托都被包裹,不或许操作个中间的嘱托
             
             其余选择这种格局定义的平地风波,能够在概念事件的类的里边直接对事件开始展览赋值,比如能够在Exec函数中增加上边那句代码:
             checkEvent = Exec;
             表示该事件能够被匹配的函数或委托赋值开头化。
             并且对事件进展赋值操作,相当于从新开始化事件之中的信托(同名委托实例),会让赋值此前对事件注册的函数都不再与事件时有发生关系,具体示例请见本类中Init伊夫nt函数的应用作用。
             */
        }
    }

    新葡亰496net 29新葡亰496net 30WebControl Codeusing System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Text;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;

    新葡亰496net 31

    namespace WebControls
    {
        [ToolboxData("<{0}:StatusList runat=server></{0}:StatusList>")]
        public class StatusList : RadioButtonList
        {
            public StatusList()
            {
                this.Init  = new EventHandler(StatusList_Init);
            }
            private void StatusList_Init(object sender, EventArgs e)
            {
                this.Items.Add(new ListItem("正常","1"));
                this.Items.Add(new ListItem("终止","2"));
                this.Items.Add(new ListItem("删除", "911"));

    CheckClass.cs

                this.SelectedIndex = 0;
                this.RepeatDirection = RepeatDirection.Horizontal;
                this.EnableViewState = false;
            }
        }
    }

    新葡亰496net 32

     

    using System;
    using System.Collections.Generic;
    using System.Text;

      3、EventHandler定义,能够通过Reflector看到

    namespace ClassLibrary
    {
        public class CheckClass
        {
            public delegate void CheckDelegate(int number);
            private CheckDelegate _checkDelete;
            public event CheckDelegate checkEvent
            {
                add
                {
                    _checkDelete = Delegate.Combine(_checkDelete, value) as CheckDelegate;
                }
                remove
                {
                    _checkDelete = Delegate.Remove(_checkDelete, value) as CheckDelegate;
                }
            }

    [Serializable, ComVisible(true)]
    public delegate void EventHandler(object sender, EventArgs e);

            public void Exec(int n)
            {
                _checkDelete(n);
                //check伊夫nt = Exec;注意展现定义事件的点子,不补助对事件一向开始展览赋值
            }

     

            /*
             delegate在编译的时候会被net编写翻译成三个类,如下:
             public delegate void CheckDelegate(int number);在编写翻译的时候会编写翻译为上面包车型客车类
             public sealed class CheckDelegate:System.MulticastDelegate
             {
                public GreetingDelegate(object @object, IntPtr method);
                public virtual IAsyncResult BeginInvoke(string name, AsyncCallback callback, object @object);
                public virtual void EndInvoke(IAsyncResult result);
                public virtual void Invoke(string name);
             }
             而System.MulticastDelegate承袭于System.Delegate,所以上面包车型客车代码才会顺遂施行
             _checkDelete = Delegate.Combine(_checkDelete, value) as CheckDelegate;
             _checkDelete = Delegate.Remove(_checkDelete, value) as CheckDelegate; 
             选取这种艺术能够令你谐和钦命事件的嘱托,以至足以让八个事件选拔同一个信托,且本人完毕add/remove,能够兑现更眼花缭乱的逻辑
             
             其余部需要要注意的是,采取这种办法定义的平地风波,固然在概念事件的类的中间都无计可施对事件直接进行赋值,举个例子曾在别的种概念格局提及的在Exec函数中拉长:
             checkEvent = Exec;
             会报错:事件“ClassLibrary.CheckClass.check伊芙nt”只好出现在  = 或 -= 的左侧
             所以在此间大家不应该操作check伊夫nt,因为它从不一致名委托实例,而因该操作_checkDelete
             */
        }
    }

      4、按键事件

    新葡亰496net 33

      按键页面

    然后是个调节台项目,须求引进下面的类库的dll文件
    Program.cs

    <asp:Button ID="Button1" runat="server" OnClick="Button1_Click"/>

    新葡亰496net 34

      CodeBehind事件

    sing System;
    using System.Collections.Generic;
    using System.Text;
    using ClassLibrary;

    protected void Button1_Click(object sender, EventArgs e) {新葡亰496net 35}

    namespace DeleGate
    {
        class Temp//定义此类是为了在代码中展现函数对信托和事件的其余一种注册格局
        {
            public delegate void TempDelegate(int u);
            public static TempDelegate td;
            public static event TempDelegate ed;
        }

      Click定义:

        class Program
        {
            private static void CheckMod(int number)
            {
                if (number % 2 == 0)
                    Console.WriteLine("输入的是偶数");
                else
                    Console.WriteLine("输入的不是偶数");
            }

    [WebCategory("Action"), WebSysDescription("Button_OnClick")]
    public event EventHandler Click
    {
        add
        {
            base.Events.AddHandler(EventClick, value);
        }
        remove
        {
            base.Events.RemoveHandler(EventClick, value);
        }
    }

            private static void CheckPositive(int number)
            {
                if (number > 0)
                    Console.WriteLine("输入的是正数");
                else
                    Console.WriteLine("输入的不是正数");
            }

      Button类的OnClick定义

            
            static void Main(string[] args)
            {
                CheckClass cc = new CheckClass();
                cc.checkEvent  = new CheckClass.CheckDelegate(CheckMod);
                cc.checkEvent  = new CheckClass.CheckDelegate(CheckPositive);

    protected virtual void OnClick(EventArgs e);

                AutoCheckClass acc = new AutoCheckClass();
                acc.checkEvent  = new AutoCheckClass.CheckDelegate(CheckMod);
                acc.checkEvent  = new AutoCheckClass.CheckDelegate(CheckPositive);
                //acc.Init伊夫nt();//奉行了那个办法后,由于对事件从新赋了值,下面对事件注册的四个函数都会失效
                
                Temp.td = CheckMod;//那意味着对信托开始展览赋值(等同于:Temp.td = new Temp.TempDelegate(CheckMod);),和对事件赋值同样,对信托开始展览赋值约等于开始化委托,会让赋值以前在委托上登记的函数与信托失去注册涉嫌。
                Temp.td  = CheckPositive;
                Console.WriteLine("Temp的结果");
                Temp.td(50);

    protected virtual void OnClick(EventArgs e)
    {
        EventHandler handler = (EventHandler) base.Events[EventClick];
        if (handler != null)
        {
            handler(this, e);
        }
    }

                Temp.ed  = CheckMod;
                Temp.ed  = CheckPositive;

     

                Console.WriteLine("cc的结果");
                cc.Exec(50);
                Console.WriteLine("acc的结果");
                acc.Exec(50);             

    几时使用委托而不应用接口,请参谋

                Console.ReadKey();
            }
        }
    }

    新葡亰496net 36

     

     

    叠合更新补充

    调用委托实例的靶子并不是调用委托函数的对象

    通过前边的事例,大家掌握到了,委托其实正是C#中的函数指针,有了信托我们能够像使用变量同样来行使函数。可是请牢记调用委托实例的对象,绝不是调用委托函数的目的。那点大家经过如下例子来证明.

    新葡亰496net 37

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace DelagateInstanceCall
    {
        //DelegateContainer是定义委托类型DelMethod和委托实例delMethod的类
        class DelegateContainer
        {
            public delegate void DelMethod();//定义一个无参数且无返回值的委托类型DelMethod
    
            public DelMethod delMethod;//定义委托类型DelMethod的委托实例delMethod
    
            public int i = 100;//定义一个int类型的变量i在类DelegateContainer之中,赋值100
        }
    
        //MethodDemo是定义委托函数DisplayMethod的类
        class MethodDemo
        {
            protected int i = 200;//定义一个int类型的变量i在类MethodDemo之中,赋值200
    
            //定义委托函数DisplayMethod
            public void DisplayMethod()
            {
                Console.WriteLine("Varible i is : "   this.i.ToString());//显示变量i的值,通过这里的值就可以知道委托函数DisplayMethod的调用对象是谁
            }
        }
    
    
        class Program
        {
            static void Main(string[] args)
            {
                DelegateContainer delCon = new DelegateContainer();//构造类DelegateContainer的对象delCon
                MethodDemo metDemo = new MethodDemo();//构造类MethodDemo的对象metDemo
    
                delCon.delMethod  = metDemo.DisplayMethod;//将函数DisplayMethod注册到委托实例delMethod,让其作为delMethod的委托函数
    
                delCon.delMethod();//调用委托实例delMethod的时候,就会调用在它上注册的委托函数DisplayMethod,那么在执行委托函数DisplayMethod时,其内部代码中的this,到底指的是
                //委托实例delMethod的调用对象delCon呢,还是委托函数DisplayMethod的调用对象metDemo呢?
                //我可以看到这里输出的结果是"Varible i is : 200",说明DisplayMethod内部的this指的是委托函数DisplayMethod本身的调用对象metDemo。这里大家很容易搞混淆,由于我们上面是通过
                //调用委托实例delCon.delMethod来调用委托函数metDemo.DisplayMethod的,看到delCon.delMethod()时大家潜意识可能就会认为由于调用委托实例delMethod的对象是delCon,就认为
                //调用委托实例delMethod上注册函数DisplayMethod的对象也是delCon,其实这是错误的。大家一定要记住委托实例只是一个壳子,它只是用来代表在其上注册的函数,但它并不会改变注册函数
                //的环境变量(比如函数的调用对象等),由于我们上面将委托函数DisplayMethod注册到委托实例delMethod时,使用的是delCon.delMethod  = metDemo.DisplayMethod,所以函数的调用
                //对象始终都是等号右边的对象metDemo,而不会是左边的对象delCon,而调用等号左边的委托实例delCon.delMethod()时,相当于就是在执行等号右边的metDemo.DisplayMethod(),
                //所以委托函数DisplayMethod的调用对象始终是metDemo。
    
                //由此请大家一定要记住,调用委托实例的对象和调用委托函数的对象没有丝毫关系,要看委托函数是谁调用的,还得要看函数注册到委托实例时,等号右边注册函数前的调用对象是谁。
    
                Console.ReadKey();
            }
        }
    }
    

    新葡亰496net 38

    从下边那一个例子,我们得以牢牢记住,调用委托实例的对象和调用委托函数的目的未有丝毫关乎,要看委托函数是什么人调用的,还得要看函数注册到委托实例时,等号左边注册函数前的调用对象是什么人。那样在运用委托时就不会出错和弄混淆。

    本文由新葡亰496net发布于奥门新萄京娱乐场,转载请注明出处:委托和事件

    关键词: