您的位置:首页 > 其它

Delegate如何进行类型转换?

2013-08-24 15:38 357 查看
我们知道对于两个不具有继承关系的两个类型,如果没有为它们定义转换器,两这之间的类型转换是不允许的,Delegate也是如此。但是有时候我们却希望“兼容”的两种Delegate类型能够进行转换,比较典型的就是表示事件的Delegate。.NET Framework为我们定义了类型EventHandler来表示事件,但是却没有规定事件的Delegate类型是EventHandler的子类。原则上讲,事件可以是任意类型的Delegate,但是我们使用的事件一般具有如下两个共同点:

不具有返回类型,或者返回类型为void;

有且只有两个输入参数,其一个参数类型为Object,第二个类型是EventArgs的子类。

using System.Runtime.InteropServices;

namespace System

{

    // 摘要:

    //     表示将处理不包含事件数据的事件的方法。

    //

    // 参数:

    //   sender:

    //     事件源。

    //

    //   e:

    //     不包含任何事件数据的 System.EventArgs。

    [Serializable]

    [ComVisible(true)]

    public delegate void EventHandler(object sender, EventArgs e);

}


 

如果事件的类型不是EventHandler的子类,我们是不可以将一个EventHandler对象对事件进行注册的。如果我们能够将EventHandler对象转换成事件对应的类型,那么就可以到达这样的目的:将同一个EventHandler注册给任意的事件。我们举个简单的例子,假设我们具有这样一个需求:对于指定的某个对象,需要在它每一个事件触发的时候我们进行响应的日志记录。具体实现如下面的代码所示,具体的日志记录实现在Log方法中,RegisterEventHandler<T>方法中我们通过反射的方式获取类型T中定义的所有Event,并将指定的EventHandler针对这些事件进行注册。由于类型可能不一致,我们通过调用自定义的EventHandlerConverter的静态方法Convert进行类型转换。[源代码从这里下载]

   1: static void RegisterEventHandler<T>(T target, EventHandler eventHandler)

   2: {

   3:     EventInfo[] events = typeof(T).GetEvents();

   4:     foreach (EventInfo eventInfo in events)

   5:     {

   6:         eventInfo.AddEventHandler(target, EventHandlerConverter.Convert(eventHandler, eventInfo.EventHandlerType));

   7:     }

   8: }


我们通过如下的代码定义了一个类型Foo,它具有Bar、Baz和Qux三个事件,其Delegate类分别是BarEventHandler、BazEventHandler和QuxEventHandler。当RaiseEvents方法被调用的时候,注册的三个事件被触发。
using System.Runtime.InteropServices;

namespace System

{

    // 摘要:

    //     表示将处理不包含事件数据的事件的方法。

    //

    // 参数:

    //   sender:

    //     事件源。

    //

    //   e:

    //     不包含任何事件数据的 System.EventArgs。

    [Serializable]

    [ComVisible(true)]

    public delegate void EventHandler(object sender, EventArgs e);

}


 

   1: public class BarEventArgs : EventArgs

   2: { }

   3: public class BazEventArgs : EventArgs

   4: { }

   5: public class QuxEventArgs : EventArgs

   6: { }

   7: 

   8: public delegate void BarEventHandler(object sender, BarEventArgs e);

   9: public delegate void BazEventHandler(object sender, BazEventArgs e);

  10: public delegate void QuxEventHandler(object sender, QuxEventArgs e);

  11: 

  12: public class Foo

  13: {

  14:     public event BarEventHandler Bar;

  15:     public event BazEventHandler Baz;

  16:     public event QuxEventHandler Qux;

  17:       

  18:     public void RaiseEvents()

  19:     {

  20:         if (null != Bar) Bar(this, new BarEventArgs());

  21:         if (null != Baz) Baz(this, new BazEventArgs());

  22:         if (null != Qux) Qux(this, new QuxEventArgs());

  23:     }

  24: }


现在我们在Main方法中编写如下的程序。从输出结果可以看出,同一个EventHandler是否能够成功注册给Foo中不同类型的三个事件。

   1: class Program

   2: {

   3:     static void Main(string[] args)

   4:     {

   5:         Foo foo = new Foo();

   6:         RegisterEventHandler<Foo>(foo, Log);

   7:         foo.RaiseEvents();

   8:     }

   9: 

  10:     static void Log(object sender, EventArgs e)

  11:     {

  12:         Console.WriteLine("{0}: {1}", sender.GetType().Name, e.GetType().Name);

  13:     }       

  14: }


输出结果:

1: Foo: BarEventArgs

2: Foo: BazEventArgs

3: Foo: QuxEventArgs


实现在EventHandlerConverter的静态方法Convert方法中的EventHandler与兼容Delegate类型之间的转换是通过“Emit”的机制实现,具体的实现逻辑如下面的代码片断所示。IsValidEventHandler方法用于验证指定的类型是否与EventHandler兼容(按照上面提及的标准进行验证),在Convert方法中我们通过Emit的方式创建了一个DynamicMethod
对象,并最终调用CreateDelegate方法将指定的Delegate对象转换成目标Delegate类型。泛型方法Convert<TDelegate>以强类型的方式指定转换的目标类型。

   1: public static class EventHandlerConverter

   2: {

   3:     public static bool IsValidEventHandler(Type eventHandlerType, out ParameterInfo[] parameters)

   4:     {

   5:         Guard.ArgumentNotNull(eventHandlerType, "eventHandlerType");

   6:         if (!typeof(Delegate).IsAssignableFrom(eventHandlerType))

   7:         {

   8:             parameters = new ParameterInfo[0];

   9:             return false;

  10:         }

  11: 

  12:         MethodInfo invokeMethod = eventHandlerType.GetMethod("Invoke");

  13:         if (invokeMethod.ReturnType != typeof(void))

  14:         {

  15:             parameters = new ParameterInfo[0];

  16:             return false;

  17:         }

  18:         parameters = invokeMethod.GetParameters();

  19:         if (parameters.Length != 2 || parameters[0].ParameterType != typeof(object))

  20:         {

  21:             return false;

  22:         }

  23:         if (!typeof(EventArgs).IsAssignableFrom(parameters[1].ParameterType))

  24:         {

  25:             return false;

  26:         }

  27:         return true;

  28:     }

  29: 

  30:     public static Delegate Convert(Delegate eventHandler, Type eventHandlerType)

  31:     {

  32:         Guard.ArgumentNotNull(eventHandler, "eventHandler");

  33:         Guard.ArgumentNotNull(eventHandlerType, "eventHandlerType");

  34: 

  35:         ParameterInfo[] destinationParameters;

  36:         if (!IsValidEventHandler(eventHandlerType, out destinationParameters))

  37:         {

  38:             throw new InvalidOperationException();

  39:         }

  40: 

  41:         if (eventHandler.GetType() == eventHandlerType)

  42:         {

  43:             return eventHandler;

  44:         }

  45: 

  46:         ParameterInfo[] sourceParameters;

  47:         if (!IsValidEventHandler(eventHandler.GetType(), out sourceParameters))

  48:         {

  49:             throw new InvalidOperationException();

  50:         }

  51:         Type[] paramTypes = new Type[destinationParameters.Length + 1];

  52:         paramTypes[0] = eventHandler.GetType();

  53:         for (int i = 0; i < destinationParameters.Length; i++)

  54:         {

  55:             paramTypes[i + 1] = destinationParameters[i].ParameterType;

  56:         }

  57:         DynamicMethod method = new DynamicMethod("WrappedEventHandler", null, paramTypes);

  58:         MethodInfo invoker = paramTypes[0].GetMethod("Invoke");

  59:         ILGenerator il = method.GetILGenerator();

  60:         il.Emit(OpCodes.Ldarg_0);

  61:         il.Emit(OpCodes.Ldarg_1);

  62:         il.Emit(OpCodes.Ldarg_2);

  63:         if (!sourceParameters[1].ParameterType.IsAssignableFrom(destinationParameters[1].ParameterType))

  64:         {

  65:             il.Emit(OpCodes.Castclass, sourceParameters[1].ParameterType);

  66:         }

  67:         il.Emit(OpCodes.Call, invoker);

  68:         il.Emit(OpCodes.Ret);

  69:         return method.CreateDelegate(eventHandlerType, eventHandler);

  70:     }

  71: 

  72:     public static TDelegate Convert<TDelegate>(Delegate eventHandler)

  73:     {

  74:         return (TDelegate)(object)Convert(eventHandler, typeof(TDelegate));

  75:     }

  76: }
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  delegate