Microsoft.NET框架程序设计--17 委托

1.认识委托

  在.NET框架中,回调函数仍然像在非托管Windows编程中一样有用和普遍。但是,.NET框架为回调函数提供了一种称为委托的类型安全的机制。

在这里,我copy一下书籍上的一个很好的例子:

namespace @delegate

{

    class Set

    {

        private Object[] items;



        public Set(int numItems)

        {

            items = new Object[numItems];

            for (int i = 0; i < numItems; i++)

                items[i] = i;

        }

        //定义一个FeedBakc委托类型

        //注意,该类型嵌套在Set 类中

        public delegate void Feedback(object value, int item, int numItems);

        public void ProcessItems(Feedback feeback)

        {

            for (int i = 0; i < items.Length; i++)

            {

                if (feeback != null)

                {

                    feeback(items[i], i + 1, items.Length);

                }

            }

        }

    }

    class Program

    {

        static void Main(string[] args)

        {

            StaticCallBacks();

            InstanceCallBacks();



        }



        private static void InstanceCallBacks()

        {

            //定义一个set集合

            Set setOfItems = new Set(5);

            Program appobj = new Program();

            setOfItems.ProcessItems(new Set.Feedback(appobj.FeedbackToFile));

        }



        private static void StaticCallBacks()

        {



            Set setOfItems = new Set(5);



            //不会有反馈

            setOfItems.ProcessItems(null);

            Console.WriteLine();



            //反馈到终端上

            setOfItems.ProcessItems(new Set.Feedback(Program.FeedbackToConsole));

            Console.WriteLine();



            //反馈到Messagebox上

            setOfItems.ProcessItems(new Set.Feedback(Program.FeedbackToMsgBox));

            Console.WriteLine();



            //同时反馈到终端上和Messagebox上

            Set.Feedback fb = null;

            fb += new Set.Feedback(Program.FeedbackToConsole);

            fb += new Set.Feedback(Program.FeedbackToMsgBox);

            Console.WriteLine();

        }



        public static void FeedbackToConsole(object value, int item, int numItems)

        {

            Console.WriteLine("Processing item{0}of {1}:{2}.", item, numItems, value);

        }



        public static void FeedbackToMsgBox(object value, int item, int numItems)

        {

            MessageBox.Show(string.Format("Processing item{0}of {1}:{2}.", item, numItems, value));

        }



        public void FeedbackToFile(object value, int item, int numItems)

        {

            StreamWriter sw = new StreamWriter("Status", true);

            sw.WriteLine("Processing item{0}of {1}:{2}.", item, numItems, value);

            sw.Close();

        }

    }

}

  

 

2.使用委托回调静态方法

也就是上面的StaticCallBacks()的调用。

3.使用委托回调实例方法

也即是上面InstanceClassbacks()函数的调用。

4.委托揭秘

public delegate void Feedback(object value,int item ,int numItems);

当遇到这段代码时,它会产生如下所示的一个完整的类定义:

public class Feedback:System.MulticastDelegate{

//构造器

public Feedback(object target,int methodPtr);

//下面的方法和源代码中指定的原型一样

public void virtual Invoke(object value,int item,item numItems);

//下面两个方法允许我们队委托进行异步回调

public virtual IAsyncResult ReginInvoke(object value,int item,int numItems,

AsyncCallback callback,object object);

public virtual void EndInvoke(IAsyncResult result);

}

所有的委托类型都继承自MulticastDelegate,他们自然也机继承了MulticastDelegate的字段、属性和方法。

MulticastDelegate中几个重要的私有字段

_target System.objet 指向回调函数被调用时应该被操作的对象,该字段用于实例化方法的回调

_methodPtr System.Int32 一个内部的整数值,CLR用它来标示回调函数

_prev System.MulticastDelegate指向另一个委托对象,该字段通常为null

MulticastDelegate类定义了两个只读实例属性:Target和Method。给定又给委托对象的引用,我们可以查询这些属性。Target属性反转一个方法回调时操作的对象引用。如果是静态方法,Target将返回null。Method属性返回一个标示回调方法的System.Reflection.MethodInfo对象。

注意所有的委托都有一个构造器,并且该构造器接受两个参数:一个对象引用和一个指向回调方法的整数。编译器通过分析源代码确定我们引用的是哪个对象和方法。其中的对象引用会被传递给target参数,一个特殊的标示方法的int32的值(由MethodDef或者MethodRef元数据标记获得)会被传递给methdPtr参数。对于静态方法而已,null会被传递给target参数。

下面看看如果回调函数是如何调用的。

当编译器遇到feedback(items[i],i+1,items.Length);

它产生的代码就像编译下面的源代码一样:

feedback.Invoke(items[i],i+1,items.Length);

5.委托史话:System.Delegate与System.MulticastDeleatge

在设计.NET框架时,提供了两种委托:一种是单播委托,一种是多播委托。他们期望继承自MulticastDelegate的类型来表示可以被连接在一起的委托对象,而继承自Delegate的类型来表示不可以被链接在一起的委托对象。

System.Delegate被设计为一个基本类型,它实现了回调一个函数所有必需的功能,MulticastDelegate类继承自Deleaget,并且为创建MulticastDelegate对象链表提供了支持。具体来讲,那些签名具有非void返回值的方法原型所表示的委托继承自System.Delegate,而使那些签名具有void返回值的方法原型所表示的委托继承自System.MulticastDelegate。

6.委托判等

Delegate重写了Object的Equals虚方法,MulticastDelegate又重写了Delegate的Equals实现。MulticastDelegate重写了Equals方法在比较两个委托对象事会首先看他们的_target和_methodPtr字段是否偶指向同一的对象和方法。如果这两个字段不匹配,那么Equals返回false。如果这连个字段都匹配,那么在看看连个委托对象是否表示委托链表的头部也就是说他们的_prev字段不为null。如果连个委托对象的_prev字段指示的链表有相同的长度,并且两个链表对应委托对象的_target和_methodPtr字段也都匹配,那么Equals将返回true,否则将返回false。)

7.委托链

MulticastDelegate对象都有以俄国私有字段_prev。该字段为指向另一个MulticastDelegate对象的引用。也就是说,每个MulticastDelegate对象都有一个指向另一个MulticstDelegate对象的引用,这使得多个委托对象可以组合成为一个链表。

Delegae类中定义了3个静态方法来帮助我们操作委托链表:

Class System.Delegate

{

//组合head和tail所表示的链表,并返回head。注意:head将是最后一个被调用的委托对象

public static Delegate Combine(Delegate tail,Delegate head);

//创建一个由委托数组表示的委托链表。注意索引为0的元素将为链表头部,并且将是最后一个被调用的委托对象

public static Delegate Combine(Delegate [] delegateArray);

//从链表中移除一个和value的回调目标/回调方法想匹配的委托,新的链表头会被返回,并且将是最后一被调用的委托对象

public static Delegate Remove(Delegate source,Delegate value);

}

当一个委托对象呗调用时,编译器会产生对该委托类型的Invoke方法的调用

(伪码描述)

class Feedback:MulticastDelegate

{

public void virtual Invoke(object value,int32 item,int32 numItems)

{

if(_prev!=null)_prve.Invoke(value,item,numItems);

_target.methodPtr(value,item,numItems);

}

}

8.C#对委托的支持

C#编译器自动为委托类型实例提供了+=和-=操作符重载支持。这两个操作符分别调用Delegate。Combine和Delegate.Remve方法。

9.对委托链调用施以更多的控制

MulticastDelegate类提供饿了一个实例方法GetInvocationList,我们可以施以它来显示调用委托链上的每一个委托读写,这事我们可以采用任何满足我们需要的算法。

10.委托与反射

System.Delegate提供了几个方法,允许我们在编译时不知道一些信息时仍能够创建调用又给委托

public class Deleaget

{

//创建一个疯子MethodInfo的delType委托

public static Delegate CreateDelegate(Type delType,MethodInfo mi);

//创建一个封装静态方法的delType委托

public static Deleaget CreateDelegaet(Type delType,Type type,stirng methodName);

//创建一个分支实例方法的delType委托

public static Delegate CreateDelegate(Type delegateType,Object obj,String methodName);

//创建一个分支实例方法的delType委托

public static Delegate CreateDeletgate(Type delegateType,Object obj,string methodName,boolean ignoreCase);

public Object DynamicInvoke(Object[] args);

}

你可能感兴趣的:(Microsoft)