第五节:委托的使用

​​​​​​一  委托解释

简单说它就是一个能把方法当参数传递的对象,而且还知道怎么调用这个方法,同时也是粒度更小的“接口”(约束了指向方法的签名)。

二 委托简单使用

一个委托类型定义了该类型的实例能调用的一类方法,这些方法含有同样的返回类型 和同样参数(类型和个数相同)。委托和接口一样,可以定义在类的外部。如下定义了一个委托类型 - Calculator:(计算机委托)

  delegate int Calculator (int x);   

 此委托适用于任何有着int返回类型和一个int类型参数的方法,如:

委托的使用
 public delegate int Calculator(int x);
        public static int  Double(int x)
        {
            return x * 2;
        }

  2.1 委托调用:

  //委托调用,(同类型,同参数类的方法)就能通过委托调用定义的这些方法,不需要实例化
            //第一种写法
            Calculator c = new Calculator(Double);
            int result = c(2);

            //第二种写法
             Calculator c1 = Double;
            int result1 = c(2);

三 用委托实现插件式编程

    解释:我们可以利用“ 委托是一个能把方法作为参数传递的对象 ” 这一特点,来实现一种插件式编程。

    3.1 例如,我们有一个Utility类,这个类实现一个通用方法(Calculate),用来执行任何有一个整型参数和整型返回值的方法。这样说有点抽象,下面来看一个例子:

namespace MyDelegate
{
    //定义一个委托类,在传建一个 类型相同,参数类型相同的方法在使用委托
    public  class BaseDelegate
    {
        public delegate int Calculator(int x);
        public static int  Double(int x)
        {
            return x * 2;
        }
    }
    //写一个公共的方法把委托当参数来使用,就可以实现所有int 类型的方法和int 类型的返回值都可以调用这个参数使用
    public  class Utility
    {
        public static void Calculate(int[] values, Calculator c)
        {
            for (int i = 0; i < values.Length; i++) values[i] = c(values[i]);
        }
    }
}

3.2 公共方法委托调用

 //在这里也可以定义委托 
    class Program
    {
        static void Main(string[] args)
        {
                int[] values = { 1, 2, 3, 4 };
                //这是调用了公共方法把委托当初 参数来调用
                // Double  就是使用了委托
                Utility.Calculate(values, Double);
                foreach (int i in values)
                {
                    Console.Write(i + " "); // 2 4 6 8      
                }
                Console.ReadKey();
        }
    }

四 多播委托

 多播委托解释:

所有的委托实例都有多播的功能。所谓多播,就像一群程序员在瞬聘网填好了求职意向后,某天有个公司发布了一个和这些程序员求职意向刚好相匹配的工作,然后这些求职者都被通知了 - “有一份好工作招人啦,你们可以直接申请去上班了!”。也就是说,一个委托实例不仅可以指向一个方法,还可以指向多个方法

例如:多播委托添加/移除案例如下

  委托的定义,和可以使用委托的方法
  
  public class MyDelegateTest
    {
        //先定义一个委托 一个无参返回类型,无参的委托方法
        public delegate void ProgressReporter();
        public static void GetMothe1()
        {
            Console.WriteLine("我是委托第一个");
        }
        public static void GetMothe2()
        {
            Console.WriteLine("我是委托第二个");
        }
        public static  void GetMothe3()
        {
            Console.WriteLine("我是委托第三个");
        }
        public static void GetMothe4()
        {
            Console.WriteLine("我是委托第四个");
        }
        public static void GetMothe5()
        {
            Console.WriteLine("我是委托第五个");
        }

    }

怎么调用委托进行新增移除委托?如下

          Console.WriteLine("**********  我在测试多播委托 添加 **************");

            ProgressReporter delegateTest =GetMothe1;
                             delegateTest += GetMothe2;
                             delegateTest += GetMothe3;
                             delegateTest += GetMothe4;
                             delegateTest += GetMothe5;
            //Invoke  作用是:调用委托方法,冲第一个到最后一个按顺序来执行
            delegateTest.Invoke();


           Console.WriteLine("********   我在测试多播委托 移除  **********");

            ProgressReporter delegateTest1 = GetMothe1;
            delegateTest1 -= GetMothe2;
            delegateTest1 -= GetMothe3;
            delegateTest1 -= GetMothe4;
            delegateTest1 -= GetMothe5;

            //Invoke  作用是:调用委托方法,冲第一个到最后一个按顺序来执行
            delegateTest.Invoke();

五 下面来探讨一下  静态方法和实例方法对于委托的区别

当一个类的实例的方法被赋给一个委托对象时,在上下文中不仅要维护这个方法,还要维护这个方法所在的实例。
System.Delegate 类的Target属性指向的就是这个实例

但对于静态方法,System.Delegate 类的Target属性是Null,所以将静态方法赋值给委托时性能更优

六 泛型委托

 解释:如果你知道泛型,那么就很容易理解泛型委托,说白了就是含有泛型参数的委托

C#  3.0 新语法在 using 后面加上 static  就不需要在创建类的实例化,可以直接使用该类的所有方法包括属性

using static MyDelegate.BaseDelegate;
using static MyDelegate.GenericDelegate;
using static MyDelegate.MyDelegateTest;
using static MyDelegate.Student;

创建泛型委托代码如下:

    /// <summary>
    /// 泛型委托
    /// </summary>
    public class GenericDelegate
    {
        /// <summary>
        /// 泛型委托,返回值 是 T 类型,参数也是 T 类型,
        /// 只要方法能匹配这个泛型委托方法就可以进行调用
        /// </summary>
        /// <param name="a"></param>
        /// <returns></returns>

        public delegate T GenericDelegateMothe<T>(T t);

        //泛型方法给泛型委托调用
        public static T GenericDelegateInt<T>(T iPaer)
        {
            Console.WriteLine($"我是 {iPaer.GetType().Name}类型 的泛型委托实现方法");
            return iPaer;
        }

        //普通方法给 泛型委托调用
        public static string  GenericDelegateString(string  sPaer)
        {
            Console.WriteLine($"我是 {sPaer.GetType().Name}类型 的泛型委托实现方法");
            return sPaer;
        }
    }

泛型委托调用

       Console.WriteLine("********* 泛型委托  泛型方法的调用  ****************   ");

            GenericDelegateMothe<int> delegateMothe = GenericDelegateInt<int>;

            delegateMothe.Invoke(7);

         Console.WriteLine("******** 泛型委托 普通方法的调用  ******************   ");

            GenericDelegateMothe<string> mothe = GenericDelegateString;

            mothe.Invoke("你好");

总结: 如果使用了泛型委托,应该要使用泛型方法来实现这个泛型委托,而不是用普通方法实现这个泛型委托,
因为 泛型方法可以适用于所有类的方法调用,而不是使用普通方法来用泛型委托, 这样就没意义了,就把泛型委托的扩展性给限制了

六  Func 和 Action 委托

 有了泛型委托,就有了一个能适用于任何返回类型和任意参数(类型和合理的个数)的通用委托,Func 和 Action。

如下所示(下面的 in 表示参数,out  表示返回结果):

delegate TResult Func <out TResult> ();
delegate TResult Func <in T, out TResult> (T arg);
delegate TResult Func <in T1, in T2, out TResult> (T1 arg1, T2 arg2); ... 一直到 T16 
-----------------------------------------
delegate void Action ();
delegate void Action <in T> (T arg);
delegate void Action <in T1, in T2> (T1 arg1, T2 arg2); ... 一直到 T16

使用 Func <out TResult> () 和  Action<in T>()  的调用

           {
                //使用Fun 来调用 有参数,有返回值的的委托泛型方法(这是普通方法)

                Func<string, string> func = GenericDelegateString;
                func.Invoke("我使用 Fun 带返回值的委托方法");

                //使用泛型委托调用
                Func<int,int> f = GenericDelegateInt<int>;
                f.Invoke(98);

                //是用 Action   来调用 无返回值 有参数的 委托
                Action<string> action = Show;

                action.Invoke("刘建峰");
            }

总结:这里这俩个委托之后,我们就可有不用特意创建委托了带参数,带返回值的就是用 Func <out TResult> (),

          带参数,不带返回值的就是用 Action<in T>() 这个委托,

 为什么有这来个委托呢?

  因为为了统一,不会被搞乱,如果委托定义多了就不知道那个创建的委托可以调用那个方法了,所以微软官方就封装了俩个委托供大家使用

7 委托的兼容

   7.1. 委托的类型兼容

delegate void D1();
delegate void D2();

D1 d1 = Method1;
D2 d2 = d1;
下面是被允许的:

D2 d2 = newD2 (d1);
对于具体相同的目标方法的委托是被视为相等的:

delegate void D();

D d1 = Method1;
D d2 = Method1;
Console.WriteLine (d1 == d2); // True
同理,对于多播委托,如果含有相同的方法和相同的顺序,也被视为相等。

    7.2 参数类型兼容、

在OOP中,任何使用父类的地方均可以用子类代替,这个OOP思想对委托的参数同样有效。如:
delegate void StringAction(string s);
class Program {     static void Main() {         
    StringAction sa = new StringAction(ActOnObject);     
    sa("hello");   
}    
     static void ActOnObject(object o) 
     {      
      Console.WriteLine(o); // hello     
     } 
}

7.3. 返回值类型兼容

delegate object ObjectRetriever();
class Program {    
 static void Main() {     
    ObjectRetriever o = new ObjectRetriever(RetriveString);   
      object result = o();        
       Console.WriteLine(result); // hello    
}     
 static string RetriveString()
   { 
      return "hello"; 
   } 
}

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值