• 第17章 委托


    本章要讨论回调函数。回调函数是一种非常有用的编程机制,它的存在已经有很多年了。

    Microsoft .Net Framework通过委托(delegate)来提供了一种回调函数机制。

    列如:委托确保回调方法是类型安全的。委托还允许顺序调用多个方法,并支持调用静态方法和实例方法。

    C#中委托是在程序运行时可以使用它们来调用不同的函数。

    举个简单的例子,你是编程的,你现在正在写一个ASP.NET网页,而JS是你不熟悉的,于是你委托你的一位同事来帮助你完成JS部分。这就是委托,把你所不能做的事情交给其他人去做。

    1.简单的委托http://www.cnblogs.com/birdshover/archive/2008/01/07/1029471.html

    那么委托需要承载哪些信息呢?首先它存储了方法名,还有参数列表(方法签名),以及返回类型,比如:

    delegate String/*返回类型*/ ProcessDelegate(Int32 i);

    蓝色部分是声明委托的关键字,红色是返回类型,黑色部分是委托的类型名,()里的就是参数部分。你要使用这个委托来做事情,必须满足一下条件:

    • 返回类型和委托的返回类型一致,这里是String类型
    • 参数列表能且只能有一个参数,并且是Int32类型

    例如:

    输出的结果是:Text1Tex2

    public delegate String ProcessDelegate(String s1, String s2);

    class Program

    {

        static void Main()

    {

     //使用委托ProcessDelegate来调用Process方法

            ProcessDelegate pd = new ProcessDelegate(new Test().Process);

            Console.WriteLine(pd("Text1", "Text2"));

        }

    }

    public class Test

    {

        public String Process(String s1, String s2)

        {

            return s1 + s2;

        }

    }

    2.回调函数

    回调函数就是把一个方法传给另一个方法去执行。它与委托不同在于,它的方法参数,返回值都可以和调用者的参数,返回值可以不一样。

    输出结果:

    Text1Text2

    Text1

    Text2

    Text2Text1

    public delegate String ProcessDelegate(String s1, String s2);

    class Program

    {

        static void Main()

        {

            Test t = new Test();

            //Process方法(调用者)调用了一个回调函数Process1,当然这里只执行了回调函数。

            //可以看出,可以把任意一个符合这个委托的方法传递进去,意思就是说这部分代码是可变的。

            //将Process1 2 3方法传递给Process方法去执行

            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;

        }

    }

    17.1初识委托

    以下代码演示了如何声明、创建和使用委托:

    using System;

    using System.Windows.Forms;

    using System.IO;

    namespace WindowsFormsApplication1

    {

        //声明一个委托类型,它的实例引用一个方法

        //指定一个回调函数的签名,该方法获取一个Int32参数,返回void

        internal delegate void Feedback(Int32 value);

        public sealed class Program

        {

            public static void Main()

            {

                StaticDelegateDemo();

                InstanceDelegateDemo();

                ChainDelegateDemo1(new Program());

                ChainDelegateDemo2(new Program());

            }

            public static void StaticDelegateDemo()

            {

                Console.WriteLine("----Static Delegate Demo----");

                Counter(1, 3, null);

                //前缀Program可选

                Counter(1, 3, new Feedback(Program.FeedbackToConsole));

                Counter(1, 3, new Feedback(FeedbackToMsgBox));

                Console.WriteLine();

            }

            private static void InstanceDelegateDemo()

            {

                Console.WriteLine("----Instance Delegate Demo----");

                Program p = new Program();

                Counter(1, 3, new Feedback(p.FeedbackToFile));

                Console.WriteLine();

            }

            private static void ChainDelegateDemo1(Program p)

            {

                Console.WriteLine("----Chain Delegate Demo 1----");

                Feedback fb1 = new Feedback(FeedbackToConsole);

                Feedback fb2 = new Feedback(FeedbackToMsgBox);

                Feedback fb3 = new Feedback(p.FeedbackToFile);

                Feedback fbChain = null;

                fbChain = (Feedback)Delegate.Combine(fbChain, fb1);

                fbChain = (Feedback)Delegate.Combine(fbChain, fb2);

                fbChain = (Feedback)Delegate.Combine(fbChain, fb3);

                Counter(1, 2, fbChain);

                Console.WriteLine();

                fbChain = (Feedback)Delegate.Remove(fbChain, new Feedback(FeedbackToMsgBox));

                Counter(1, 2, fbChain);

            }

            private static void ChainDelegateDemo2(Program p)

            {

                Console.WriteLine("----Chain Delegate Demo 2----");

                Feedback fb1 = new Feedback(FeedbackToConsole);

                Feedback fb2 = new Feedback(FeedbackToMsgBox);

                Feedback fb3 = new Feedback(p.FeedbackToFile);

                Feedback fbChain = null;

                fbChain += fb1;

                fbChain += fb2;

                fbChain += fb3;

                Counter(1, 2, fbChain);

                Console.WriteLine();

                fbChain -= new Feedback(FeedbackToMsgBox);

                Counter(1, 2, fbChain);

            }

            private static void Counter(Int32 from, Int32 to, Feedback fb)

            {

                for (Int32 val = from; val <= to; val++)

                {

                    //如果指定了任何回调函数,就调用它们

                    if (fb != null)

                        fb(val);

                }

            }

            private static void FeedbackToConsole(Int32 value)

            {

                Console.WriteLine("Item=" + value);

            }

            private static void FeedbackToMsgBox(Int32 value)

            {

                MessageBox.Show("Item=" + value);

            }

            private void FeedbackToFile(Int32 value)

            {

                StreamWriter sw = new StreamWriter("Status", true);

                sw.WriteLine("Item=" + value);

                sw.Close();

            }

        }

    }

    17.2用委托回调静态方法

    在StaticDelegateDemo方法中,第一次调用Counter方法时,为第三个参数传递的是null。由于Counter的fb参数收到的是null,所以每个数据项在处理时,都不会调用回调函数。

    接着StaticDelegateDemo方法再次调用Counter方法,为第三个参数传递一个新构造的Feedback委托对象。委托对象(new操作符新建的Feedback对象)是方法的一个包装器(wrapper),使方法能通过包装器来间接回调。

    在本例中,静态方法的完整名称Program.FeedbackToConsole被传给Feedback委托类型的构造器。表明FeedbackToConsole就是要包装的方法。new操作符返回的引用作为Counter的第三个参数来传递。

    在一个类型中,可以通过委托来调用另一个类型的私有成员时,只要委托对象是有具有足够安全性和可访问性的代码创建时,便不会有问题。

    这个例子中的所有操作都是类型安全的。例如,在构造Feedback委托对象时,编译器确保Program的FeedbackToConsole方法的签名,兼容于Feedback委托定义的签名。具体的说,FeedbackToConsole必须获取一个参数,而且两者都必须有相同的返回类型(void)。

    将一个方法绑定到委托时,C#和CLR都允许引用类型的协变形和逆变性。

    17.3用委托回调实例方法

    InstanceDelegateDemo中构造了一个名为p的Program对象。这个Program对象没有定义任何实例字段和属性。向Counter委托类型的构造函数传递的是p.FeedbackToFile,这导致委托包装对FeedbackToFile方法的一个引用,这个方法是实例方法,而不是静态方法。当Counter调用由其fb实参标识的回调函数时,会调用FeedbackToFile实例方法。

    17.4委托揭秘

    从表面看,委托似乎很容易使用:用C#的delegate关键字,用熟悉的new操作符构造委托实例。

    CLR和编译器做了大量的工作来隐藏委托的复杂性。

  • 相关阅读:
    基础
    树梅派线程
    超声波
    电脑版微信双开多开
    子类能不能重写父类的构造方法
    window8taskost.exe一直占用cpu
    windows下rocketmq安装
    spring循环依赖问题
    线程池的种类
    并行和并发有什么区别?
  • 原文地址:https://www.cnblogs.com/chrisghb8812/p/5618307.html
Copyright © 2020-2023  润新知