您的位置:首页 > 其它

不具有继承关系的Delegate如何进行类型转换?

2012-11-03 10:56 585 查看
[code] static void RegisterEventHandler<T>(T target, EventHandler eventHandler)

{

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

foreach (EventInfo eventInfo in events)

{

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

}

}

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

[code]
[code] public class BarEventArgs : EventArgs

{}

public class BazEventArgs : EventArgs

{}

public class QuxEventArgs : EventArgs

{}


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

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

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


public class Foo

{

 public event BarEventHandler Bar;

 public event BazEventHandler Baz;

 public event QuxEventHandler Qux;


 public void RaiseEvents()

{

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

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

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

}

}

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

[code]
[code] class Program

{

 static void Main(string[] args)

{

 Foo foo = new Foo();

 RegisterEventHandler<Foo>(foo, Log);

 foo.RaiseEvents();

}


 static void Log(object sender, EventArgs e)

{

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

}

}

[/code]
[/code]
输出结果:

[code]
[code] Foo: BarEventArgs

Foo: BazEventArgs

Foo: QuxEventArgs

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

[code]
[code] public static class EventHandlerConverter

{

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

{

 Guard.ArgumentNotNull(eventHandlerType, "eventHandlerType");

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

{

 parameters = new ParameterInfo[0];

 return false;

}


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

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

{

 parameters = new ParameterInfo[0];

 return false;

}

 parameters = invokeMethod.GetParameters();

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

{

 return false;

}

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

{

 return false;

}

 return true;

}


 public static Delegate Convert(Delegate eventHandler, Type eventHandlerType)

{

 Guard.ArgumentNotNull(eventHandler, "eventHandler");

 Guard.ArgumentNotNull(eventHandlerType, "eventHandlerType");


 ParameterInfo[] destinationParameters;

 if (!IsValidEventHandler(eventHandlerType, out destinationParameters))

{

 throw new InvalidOperationException();

}


 if (eventHandler.GetType() == eventHandlerType)

{

 return eventHandler;

}


 ParameterInfo[] sourceParameters;

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

{

 throw new InvalidOperationException();

}

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

 paramTypes[0] = eventHandler.GetType();

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

{

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

}

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

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

 ILGenerator il = method.GetILGenerator();

 il.Emit(OpCodes.Ldarg_0);

 il.Emit(OpCodes.Ldarg_1);

 il.Emit(OpCodes.Ldarg_2);

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

{

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

}

 il.Emit(OpCodes.Call, invoker);

 il.Emit(OpCodes.Ret);

 return method.CreateDelegate(eventHandlerType, eventHandler);

}


 public static TDelegate Convert<TDelegate>(Delegate eventHandler)

{

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

}

}

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