C# Delegate 委托

1、委托Delegate实质

由一个修饰符+  delegate,跟方法的定义比较类似,也需要声明参数和返回值。声明一个委托,就是声明一种方法签名(参数+返回值),只要是和声明委托方法签名相同的方法,都可以被委托实例托管。

理解:具有相同方法签名的方法(method),他们的调用都可以通过相同方法签名的委托(class)去实现

比如现在有很多排队的需求:排队买奶茶、排队拿号买房。。。,这些需求可让一个排队服务机构去完成,这个机构只需要定义一项委托服务:指派一个人去排队获取xxx

public delegate object WaitGetAccesss(Person person)

还比如快递服务是不是也是类似的场景,快递的本质是把东西从地点A搬运到地点B,同样可以定义public delegate void WaitGetAccesss(object obj,area A,area B);只需要告知要运输的货物、起始地点A、目的地点B即可(这里只针对运输的部分,不包含派送的部分)

几乎所有的快递运输都可以通过这个方式去完成,无论是数码产品、食品这些

自己能做的事情,让这个排队服务机构完成,这不就是现实世界里委托的含义吗?

public delegate void MyFirstDelegate()

委托的实质是一个类,通过反编译得到MyFirstDelegate如下,这个类继承MulticastDelegate,类的内部包含ctor的构造函数,Invoke、BeginInvoke、EndInvoke方法

.class nested public auto ansi sealed MyFirstDelegate
        extends [System.Runtime]System.MulticastDelegate
    {
        // Methods
        .method public hidebysig specialname rtspecialname 
            instance void .ctor (
                object 'object',
                native int 'method'
            ) runtime managed 
        {
        } // end of method MyFirstDelegate::.ctor

        .method public hidebysig newslot virtual 
            instance int32 Invoke (
                int32 x,
                int32 y
            ) runtime managed 
        {
        } // end of method MyFirstDelegate::Invoke

        .method public hidebysig newslot virtual 
            instance class [System.Runtime]System.IAsyncResult BeginInvoke (
                int32 x,
                int32 y,
                class [System.Runtime]System.AsyncCallback callback,
                object 'object'
            ) runtime managed 
        {
        } // end of method MyFirstDelegate::BeginInvoke

        .method public hidebysig newslot virtual 
            instance int32 EndInvoke (
                class [System.Runtime]System.IAsyncResult result
            ) runtime managed 
        {
        } // end of method MyFirstDelegate::EndInvoke

    } // end of class MyFirstDelegate

2、委托的定义及执行

定义

委托的参数方法的签名要和委托的方法签名一致(即要有相同的参数及返回值)

        public delegate int NumberHandleDelegate(int a,int b);
        public static int AddNum(int a, int b)
        {
            return a+b;
        }
        //标准写法
        NumberHandleDelegate numberHandleDelegate1 = new NumberHandleDelegate(AddNum);
        //语法糖,编译器使用的便捷功能,帮忙省略了new NumberHandleDelegate的编写
        NumberHandleDelegate numberHandleDelegate2 = AddNum;
        //lambda表达式(匿名方法)
        NumberHandleDelegate numberHandleDelegate3 = (int a, int b) => a + b;

执行

{
                Student s = new Student();
                int num = s.numberHandleDelegate1.Invoke(3, 5);
                Console.WriteLine($"num:{num}");
                //结果打印:num:8
            }

3、实际的应用

3.1应用一

        public enum PersonType
        {
            Student = 1,

            Teacher = 2
        }

现在想针对不同的人有不同的打招呼的方式,有以下两种方案

        //方案1:定义枚举,通过枚举判断,分别给出不同的问候方式;
        public void SayHi(PersonType type)
        {
            switch (type)
            {
                case PersonType.Student:
                    Console.WriteLine("同学好");
                    break;
                case PersonType.Teacher:
                    Console.WriteLine("老师好");
                    break;
                default:
                    throw new Exception("没有找到具体类型");
            }
        }
        //方案2:根据不同的类型的人,分别定义不同的问候方式
        public void SayStudentHi()
        {
            Console.WriteLine("同学好");
        }

        public void SayTeacherHi()
        {
            Console.WriteLine("老师好");
        }

优劣分析

        //场景1:如果增加一个类型的人 
        //方案1:多种分支判断    ---如果增加一个类型的人------增加一个校长;---校长好!
        //    问题:SayHi方法不稳定,一旦增加一个类型的人;SayHi方法就需要修改;方法的所有逻辑都选哟重新测试. 一个方法中有多种业务逻辑---业务逻辑耦合
        //方案2:每个方法都式独立的:
        //    问题:---如果增加一个类型的人---增加一个方法;功能独立,对其他的功能内部不影响;


        //场景2:如果需要增加一个功能的业务逻辑呢?--打招呼后再握手
        //方案1:增加功能的业务逻辑很方便;只需要在方法内加上 Console.WriteLine("握手");
        //方案2:增加公共逻辑--每个方法都需要增加--增加的代码都是一样的,----大量的重复代码;

利用委托能覆盖以上两种场景,完美解决以上问题

        //定义一个打招呼的委托
        public delegate void SayHiDelegate();
        //定义一个公共方法,参数为打招呼的委托
        public void SayHiPerfect(SayHiDelegate sayHiDelegate)
        {
            sayHiDelegate.Invoke();
            Console.WriteLine("握手");
        }

调用:

//方案三:
                student.SayHiPerfect(student.SayStudentHi);
                student.SayHiPerfect(student.SayTeacherHi);

3.2应用二、面向切面编程

 

上一篇:Oracle多表连接,提高效率,性能优化 (转)


下一篇:malloc分配内存问题