C# 委托

135 阅读4分钟

委托

委托(delegate)是函数指针的升级版

委托的缺点:

​ 1、会导致可读性下降,debug难度增加

​ 2、把委托回调、异步调用和多线程绞在一起,会使代码的维护比难

​ 3、委托使用不当会但是内存泄漏和程序性能下降

Action委托(无参数委托)

action委托通常是用来表示一个不带参数且没有返回值的方法,相当于是用来去对方法的封装

 class Proparm
    {
        static void Main(string[] args)
        {

            Calcutor room = new Calcutor();

            Action action = new Action(room.Report);
            ////Action是一种预定义委托
            //action();//可以通过它来去间接的调用委托
        }
    }
    class Calcutor
    {
        public void Report()
        {
            Console.WriteLine("我就是我,你就是你");
        }
        public int Add(int x, int y)
        {
            int result = x + y;
            return result;
        }
        public int Min(int x, int y)
        {
            int result = x - y;
            return result;
        }


    }
Func泛型委托

通过泛型去约束数据的类型和返回值的类型去达到效果

 class Proparm
    {
        static void Main(string[] args)
        {
            Calcutor room = new Calcutor();
            ////第二种委托func  它是一个泛型委托 2个参数的类型和返回值的类型
            Func<int, int, int> func1 = new Func<int, int, int>(room.Add);
            Func<int, int, int> func2 = new Func<int, int, int>(room.Min);

            int x = 100;
            int y = 200;
            int z = 0;
            z = func1(x,y);
            Console.WriteLine(z);
            z = func2(x, y);
            Console.WriteLine(z);
        }
    }
    class Calcutor
    {
        public void Report()
        {
            Console.WriteLine("我就是我,你就是你");
        }
        public int Add(int x, int y)
        {
            int result = x + y;
            return result;
        }
        public int Min(int x, int y)
        {
            int result = x - y;
            return result;
        }
    }

自定义委托(delegate)

自定义委托:其实自定义委托跟自定义类是差不多的,跟类是平级的

所以在创建自定义委托的时候通常是直接在命名空间的下一级进行委托的声明,但也可以在类中进行声明 public delegate double Call(double x, double y); 通过关键字 delegate去进行声明,同时对委托的类型进行一个类型约束 在使用方面,跟上面2个委托的使用方法一样,通过实例化方法对象,然后进行调用即可 注意:委托与所封装的方法必须兼容,就是委托的类型与数据的类型必须是一致的

 public delegate double Call(double x, double y);
 
 //自定义委托定义补充
    class Program
    {
        static void Main(string[] args)
        {
            Delt delt = new Delt(M1);
            Student stu = new Student();
            delt += stu.SayHello;
            //可以通过事件订阅去同时或者2个或者多个方法
            delt();  //现在delt这个委托实例身上就有2种方法,SayHello + M1


            Delt2 b = new Delt2(Add); // 第二种自定义委托,拥有参数的委托
            //   delegate int Delt2(int x, int y);
            int res = b(100, 200);
            Console.WriteLine(res);


            Delt3<int> c = new Delt3<int>(Add); // 第三种泛型委托  
            // delegate T Delt3<T>(T a, T b);
            int aa = c(100, 200);

            Delt3<double> d = new Delt3<double>(Man);
            double bb = d(3.1,1.9);

            Console.WriteLine(bb);
            Console.WriteLine(aa);

        }

        static double Man(double x,double y)
        {
            return x * y;
        }
        static void M1()
        {
            Console.WriteLine("你好");
        }

        static int Add(int x,int y)
        {
            return x + y;
        }
    }

    delegate void Delt();

    delegate int Delt2(int x, int y);

    delegate T Delt3<T>(T a, T b);
    
    class Student
    {
        public void SayHello()
        {
            Console.WriteLine("学生");
        }
    }
委托方法:模板方法(跟工厂模式差不多,本质上很抽象)

直接上代码看,多写点注释 你好我好,它也好

class Program
{
    static void Main(string[] args)
    {
        /*
        A:玩具
        B:把玩具打包
        C:顾客
         Factory:工厂
        */

        Factory factory = new Factory();  // 将工厂实例化
        C c = new C();  //同时也对顾客进行一个实例化
        Func<A> func1 = new Func<A>(factory.apple);  //通过委托去读取 工厂内的东西
        Func<A> func2 = new Func<A>(factory.banner);

        B box1 = c.Geting(func1); //
        B box2 = c.Geting(func2);
        /*
         首先,我们通过调用 Geting 方法传递了一个名为 func1 的委托作为参数。
         这个委托表示一个没有参数且返回类型为 A 的方法。
         在 Geting 方法内部,首先创建了一个类型为 B 的对象 box。
         然后通过调用传递进来的 func1 委托来获取一个类型为 A 的对象,
        返回的 A 对象将被赋值给 box.Mybox 属性。
        将 box1 变量声明为类型为 B,并将其赋值为 c.Geting(func1) 的返回值,即封装了 A 对象的 B 对象。
         */

        Console.WriteLine(box1.Mybox.Name);
        Console.WriteLine(box2.Mybox.Name);


    }

    class A //把它看成是一个用类去定义的类型
    {
        public string Name { get; set; }
    }

    class B
    {
        public A Mybox { get; set; }
        //class B 相当于是对A进行了一个封装,现在B自己里面拥有了A里面有的东西 Mybox.Name
   
    }

    class C
    {
        public B Geting(Func<A> getProdouct)
            //新建了一个Geting方法,这个方法的类型是String类型
            //Func<>委托,它是一个没有参数只有返回值的委托,这个返回值的类型是string
        {
            B box = new B(); //先是实例化对象 
            A a = getProdouct();  
            // 通过这个委托方法来去获取A的实例化 也是如果你不是去进行实例化是无法得到A的对象
            box.Mybox = a; // 这里就简单一些,因为我们这是通过 B 来当作类型,无法直接的去读取A,
       //但是 B class中有一个Mybox的方法这个方法的类型是A,那么就可以通过访问这个方法去进行对A对象的读取
            return box;
        }
    }

    class Factory
    {
        public A apple()
        {
            A a = new A();
            a.Name = "苹果";
            return a;
        }

        public A banner()
        {
            A a = new A();
            a.Name = "香蕉";
            return a;
        }
    }
}

总结:委托功能很强大, 而且高级委托涉及到多线程,现在只是先打个逻辑基础,到后续把多线程补了,再回来研究高级委托