《CLR Via C#(第三版)》 第十七章

第17章 委托

17.1 初识委托

using System;

namespace EnumApp
{
    static class Program
    {
        static void Main()
        {
            MyDelegate[] ds = { new MyDelegate(Print1), new MyDelegate(Print2) };
            int[] a = { 100, 1000 };
            Execute(a, ds, a.Length);
        }
        public static void Print1(int i)
        {
            Console.WriteLine(i);
            Console.WriteLine("Print1");
            Console.WriteLine();
        }
        public static void Print2(int i)
        {
            Console.WriteLine(i);
            Console.WriteLine("Print2");
            Console.WriteLine();
        }
        public static void Execute(int[] a, MyDelegate[] ds, int length)
        {
            for (int i = 0; i < length; i++)
                ds[i](a[i]);
        }
    }
    public delegate void MyDelegate(int i);
}

17.2 用委托回调静态方法

将一个方法绑定到委托时,C#和CLR都允许引用类型的协变性(covariance)和逆变性(contravariance)。协变性是指方法能返回从委托的返回类型派生的一个类型。逆变性是指是方法获取的参数可以是委托的参数类型的基类。

协变性和逆变性只能应用于引用类型,不能用于值类型和void。

17.4 委托揭秘

由于 委托是类,所以凡是能够定义类的地方,都能定义委托。

由于所有委托类型都派生自MulticastDelegate,所以他们继承了MulticastDelegate的字段属性和方法。

Delegate类定义了两个只读的公共实例属性:Target和Method。

Target属性返回一个引用,它指向回调方法要操作的对象。Method属性返回对于个System.Reflection.MethodInfo对象的引用,该对象标识了回调方法。

可以调用Invoke方法来执行回调方法。

 public static void Execute(int[] a, MyDelegate[] ds, int length)
        {
            for (int i = 0; i < length; i++)
            {
                Console.WriteLine(ds[i].Target == null ? "null" : ds[i].Target); //null
                Console.WriteLine(ds[i].Method); //Print#(int32)
                ds[i].Invoke(a[i]);//ds[i](a[i]);
            }
        }
17.5 用委托回调许多方法(委托链)

使用 Delegate类的公共静态方法Combine,可以将一个委托添加到链中。

使用Delegate的公共静态方法Delete,可以从链中删除委托。如果链中删除了仅有的一个元素,Remove会返回null。

result变量将只包含调用的最后一个委托的结果,前面的返回值会被丢弃。

+=,-+这些操作符分别调用Delegate.Combine和Delegate.Remove。

MulticastDelegate类提供了一个实例方法GetInvocationList,用于显式调用链中的每一个委托,同时使用符合自己需要的任何算法。

using System;

namespace EnumApp
{
    static class Program
    {
        static void Main()
        {
            Class1 c1 = new Class1();
            MyDelegate d1 = new MyDelegate(c1.Method1);
            MyDelegate d2 = new MyDelegate(c1.Method2);
            MyDelegate d3 = new MyDelegate(c1.Method3);

            MyDelegate d0 = null;
            d0 = (MyDelegate)Delegate.Combine(d0, d1);
            d0 = (MyDelegate)Delegate.Combine(d0, d2);
            d0 = (MyDelegate)Delegate.Combine(d0, d3);

            Console.WriteLine(d0.Invoke(2)); //最后加载的委托的执行result 0

            foreach (var d in d0.GetInvocationList())
                d.DynamicInvoke(3);
        }
    }
    public delegate int MyDelegate(int i);

    public class Class1
    {
        public int Method1(int i) 
        {
            Console.WriteLine("i*i={0}", i * i);
            return i * i;
        }
        public int Method2(int i)
        {
            Console.WriteLine("i+i={0}", i + i);
            return i + i;
        }
        public int Method3(int i)
        {
            Console.WriteLine("i-i={0}", i - i);
            return i - i;
        }
    }
}

17.6 委托定义太多(泛型委托)

FCL提供了17个Action委托,它们从无参数一直到最多16个参数。

除了Action委托,.Net Framework还提供了17个Func函数,它们允许回调方法返回一个值。

using System;

namespace EnumApp
{
    static class Program
    {
        static void Main()
        {
            Class1 c1 = new Class1();
            Func<int, int> d1 = new Func<int, int>(c1.Method1);
            Console.WriteLine(d1.Invoke(2)); 
        }
    }

    public class Class1
    {
        public int Method1(int i) 
        {
            return i * i;
        }
    }
}

17.7 C#为委托提供的简化语法

lambda表达式可在编译器预计会看到一个委托的地方使用。编译器看到这个lambda表达式后,会在类中自动定义一个新的私有方法。这个新方法称为匿名函数,因为方法的名字是编译器自动创建的。

            Class1 c1 = new Class1();
            Func<int, int> d1 = new Func<int, int>(p => { Console.WriteLine(p * p); return p * p; });
            d1.Invoke(3);
17.8 委托和反射

所有CreateDelegate方法构造的都是从Delegate派生的一个类型的新对象,具体类型由第一个参数type来标识。MethodInfo参数指出应该回调的方法。

using System;
using System.Reflection;

namespace EnumApp
{
    internal delegate int MyDelegate(int i);

    static class Program
    {
        static void Main()
        {
            Class1 c1 = new Class1();
            Delegate d = Delegate.CreateDelegate(typeof(MyDelegate), new Class1(), typeof(Class1).GetMethod("Method1", BindingFlags.Public | BindingFlags.Instance), false);
            Console.WriteLine(d.DynamicInvoke(100));
        }
    }

    public class Class1
    {
        public int Method1(int i)
        {
            return i * i;
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值