【发布时间】:2009-03-05 11:16:47
【问题描述】:
我有一个带有类的程序集,该类使用委托和自定义事件参数定义自定义事件。现在我必须通过我的代码动态加载这个程序集并创建这个类的实例。到这里为止我很好。现在我必须为使用自定义委托的类对象引发的事件提供事件处理程序。如何向使用反射的类引发的事件添加事件处理程序?
【问题讨论】:
我有一个带有类的程序集,该类使用委托和自定义事件参数定义自定义事件。现在我必须通过我的代码动态加载这个程序集并创建这个类的实例。到这里为止我很好。现在我必须为使用自定义委托的类对象引发的事件提供事件处理程序。如何向使用反射的类引发的事件添加事件处理程序?
【问题讨论】:
这是执行此操作的代码:
class Program
{
static void Main(string[] args)
{
// Create publisher.
var pub = Activator.CreateInstance(typeof(Publisher));
// Get the event.
var addEvent = typeof(Publisher).GetEvent("Event");
// Create subscriber.
var sub = Activator.CreateInstance(typeof(Subscriber));
// Get the method.
var handler = typeof(Subscriber).GetMethod("Handle");
// Create a valid delegate for it.
var handlerDelegate = MakeEventHandlerDelegate(handler, sub);
// Add the event.
addEvent.AddEventHandler(pub, handlerDelegate);
// Call the raise method.
var raise = typeof(Publisher).GetMethod("Raise");
raise.Invoke(pub, new object[] { "Test Value" });
Console.ReadLine();
}
static Delegate MakeEventHandlerDelegate(MethodInfo methodInfo, object target)
{
ParameterInfo[] info = methodInfo.GetParameters();
if (info.Length != 2)
throw new ArgumentOutOfRangeException("methodInfo");
if (!typeof(EventArgs).IsAssignableFrom(info[1].ParameterType))
throw new ArgumentOutOfRangeException("methodInfo");
if (info[0].ParameterType != typeof(object))
throw new ArgumentOutOfRangeException("methodInfo");
return Delegate.CreateDelegate(typeof(EventHandler<>).MakeGenericType(info[1].ParameterType), target, methodInfo);
}
}
class Args : EventArgs
{
public string Value { get; set; }
}
class Publisher
{
public event EventHandler<Args> Event;
public void Raise(string value)
{
if (Event != null)
{
Args a = new Args { Value = value };
Event(this, a);
}
}
}
class Subscriber
{
public void Handle(object sender, Args args)
{
Console.WriteLine("Handle called with {0}.", args.Value);
}
}
【讨论】:
一个事件是一个多播委托,您可以将该事件检索为 System.Delegate 的一种类型,使用 Delegate.Combine 组合两个实例,然后将委托设置为组合委托。
C# 有很好的简写语法:
class SomeClass
{
public event Action<string> TextEvent;
}
你会这样写:(我觉得有点懒,不会检查这个,你必须自己解决问题)
var obj = // instance of SomeClass...
var t = typeof(SomeClass); // you need the type object
var member = t.GetEvent("TextEvent");
member.AddEventHandler(obj, new Action<string>(delegate(string s)){}); // done!
【讨论】:
我以前不得不这样做,真的很痛苦 - 最终遇到了这个tutorial。
是否有可能在另一个程序集中有一个接口,您可以使用它来将事件与反射联系起来?只是一个想法......
【讨论】:
我可能遗漏了一些东西,但是如果您知道需要连接的事件的名称和签名,那么您大概知道公开该事件的类型。在这种情况下,为什么需要使用反射?只要你有一个正确类型的引用,你就可以以正常的方式附加一个处理程序。
【讨论】: