EKsumic's Blog

let today = new Beginning();

Click the left button to use the catalog.

OR

C#委托(下)

上一篇:C#委托(上)

✦ 当一个实例方法被赋值给委托对象的时候,这个委托对象不仅要保留着对方法的引用,还要保留着方法所属实例的引用
✦ System. Delegate的Target属性就代表着这个实例。
✦ 如果引用的是静态方法,那么Target属性的值就是null。

 

举例:

public delegate void ProgressReporter(int percentComplete);
    class X
    {
        public void InstanceProgress(int percentComplete) 
            => Console.WriteLine(percentComplete);
    }
    public class Program
    {
        static void Main(string[] args)
        {
            X x = new X();
            ProgressReporter p = x.InstanceProgress;
            p(99);
            Console.WriteLine(p.Target == x); //True --对实例的引用
            Console.WriteLine(p.Method); //Void InstanceProgress(Int32)  --对方法的引用
            Console.ReadKey();
        }
    }

输出结果:

99

True

Void InstanceProgress(Int32)

 

泛型委托:

public delegate T Transformer<T>(T arg);

    public class Util
    {
        public static void Transform<T>(T[] values,Transformer<T> t)
        {
            for (int i = 0; i < values.Length; i++)
                values[i] = t(values[i]);
        }
    }
    class Program
    {
        static int Square(int x) => x * x;
        static void Main(string[] args)
        {
            int[] values = { 1, 2, 3 };
            Util.Transform(values, Square); //Hook in Square
            foreach (int i in values)
                Console.Write(i + " "); //1 4 9
            Console.ReadKey();
        }
    }

简写:

Util.Transform(values, Square);
Util.Transform<int>(values, Square);

输出:

1 4 9

 

使用泛型委托,就可以写出这样一组委托类型——它们可调用的方法可以拥有任意的返回类型和任意(合理)数量的参数。

委托结合事件是能够改变项目框架的东西。

 

Func和Action的源码定义:

 

Func和Action

 

举例:

 public class Util
    {
        public static void Transform<T>(T[] values,Func<T,T> t)
        {
            for (int i = 0; i < values.Length; i++)
                values[i] = t(values[i]);
        }
    }
    class Program
    {
        static int Square(int x) => x * x;
        static void Main(string[] args)
        {
            int[] values = { 1, 2, 3 };
            Util.Transform(values, Square); //Hook in Square
            foreach (int i in values)
                Console.Write(i + " "); //1 4 9
            Console.ReadKey();
        }
    }

输出:

1 4 9

 

声明委托的这句必要性是,

以后用别的方法的时候,能调用(所声明的同类型的)方法,

那这样的话,甚至可以简写。

 

简写:

public delegate T Transformer<T>(T arg);

Transformer<T> t

To:

Func<T,T> t

 

委托vs接口

委托可以解决的问题,接口都可以解决。

什么情况下更适合使用委托而不是接口呢?当下列条件之一满足时:
✦ 接口只能定义一个方法
✦ 需要多播能力
✦ 订阅者需要多次实现接口

 

委托的兼容性-委托类型

✦ 委托类型之间互不相容,即使方法签名一样:

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

D1 d1=Method1;
D2 d2=d1;    // Compile-time error


委托的兼容性-委托实例
✦ 如果委托实例拥有相同的方法目标,那么委托实例就认为是相等的。

delegate void D();
....

D d1=Method1;
D d2=Method1;
Console.WriteLine(d1==d2);     // True

委托的兼容性-参数
✦ 当你调用一个方法时,你提供的参数(argument)可以比方法的参数(parameter)定义更具体。
✦ 委托可以接受比它的方法目标更具体的参数类型,这个叫ContraVariance。

 

 

✦ 和泛型类型参数一样,委托的variance仅支持引用转换。

 

引用类型:基类为Objcet

值类型:均隐式派生自System.ValueType:

值类型: byte,short,int,long,float,double,decimal,char,bool 和 struct 统称为值类型。
引用类型: string 和 class统称为引用类型。

 

举个例子:

以上述图片为例:

object可以具体为string;

long不能具体为int,因为发生了数值转换。

object也不可以具体为int,因为发生了装箱操作。

所以注意:

委托的协变或逆变仅支持引用转换。

这个和泛型的类型参数是一样的。

 

委托的兼容性-返回类型

✦调用方法时,你可以得到一个比请求的类型更具体的类型的返回结果。

✦委托的目标方法可以返回比委托描述更具体地类型的返回结果,Covariance。

 

Covariance——协变(协方差)。

 

object to string

 

泛型委托类型参数的variance

Covariance,out

ContraVariance,in


参数只作为输出就用out来修饰,只作为输入就用in。

This article was last edited at 2020-12-13 15:49:31

* *