我有以下代码:
namespace ConsoleApplication
{
static void Main(string[] args)
{
Device device = new Device();
device.Command += new EventHandler<DeviceSpecialArgs>(device_Command);
}
public static void device_Command(Object source, DeviceSpecialArgs args)
{
Console.WriteLine("Command: {0}, Reguest: {1}", args.Command, args.Request);
}
}
}
我必须做完全相同的事情,但是包含Device和DeviceSpecialArgs类型的程序集需要在运行时加载。我知道如何用反射加载程序集,但我发现事件处理部分令人费解:
namespace ConsoleApplication
{
static void Main(string[] args)
{
// Load the assembly
string dllPath = @"C:TempDevice.dll"
Assembly asm = Assembly.LoadFrom(dllPath);
// Instanciate Device
Type deviceType = asm.GetType("Device");
object device = Activator.CreateInstance(deviceType);
// How do I subscribe to the Command event?
}
// args would normally be a DeviceSpecialArgs but since that type is
// unknown at compile time, how do I prototype the handler?
public static void device_Command(Object source, ??? args)
{
Console.WriteLine("Command: {0}, Reguest: {1}", args.Command, args.Request);
}
}
如何使用反射订阅事件?此外,我应该如何原型处理程序本身,因为类型的"args"是未知的在编译时?仅供参考,我是c# 3和。net 3.5。
首先,看看MAF。
另一种方法是向第一个程序集添加对第二个程序集的引用。然后在第二个程序集中创建两个接口,并在第一个程序集中创建类来实现它们:
public interface IDeviceSpecialArgs
{
string Command { get; }
string Request { get; }
}
public interface IDevice
{
event EventHandler<IDeviceSpecialArgs> Command;
}
第一个汇编:
public sealed class DeviceSpecialArgs : EventArgs, IDeviceSpecialArgs
{
private readonly string command;
private readonly string request;
public string Command
{
get { return command; }
}
public string Request
{
get { return request; }
}
public DeviceSpecialArgs(string command, string request)
{
this.command = command;
this.request = request;
}
}
public class Device : IDevice
{
public event EventHandler<IDeviceSpecialArgs> Command;
...
}
在第二个程序集中,只需将新实例化的对象强制转换为相应的接口:
IDevice device = Activator.CreateInstance(deviceType) as IDevice;
现在您可以订阅Command
事件,因为它是在IDevice
接口中声明的:
device.Command += new EventHandler<IDeviceSpecialArgs>(device_Command);
EDIT:如果您无法控制正在加载的程序集,请尝试以下代码。它只是创建了第二个参数的EventArgs
类型的处理程序,并使用反射来获取其属性:
internal class DeviceEvent
{
private readonly Type deviceType;
private readonly Type deviceSpecialArgsType;
public DeviceEvent()
{
// Load the assembly
const string dllPath = @"C:TempDevice.dll";
Assembly asm = Assembly.LoadFrom(dllPath);
// Get types
deviceType = asm.GetType("Device");
deviceSpecialArgsType = asm.GetType("DeviceSpecialArgs");
// Instantiate Device
object device = Activator.CreateInstance(deviceType);
// Subscribe to the Command event
deviceType.GetEvent("Command").AddEventHandler(device, (Delegate.CreateDelegate(typeof(EventHandler), GetType().GetMethod("Device_Command", BindingFlags.NonPublic))));
}
private void Device_Command(object sender, EventArgs e)
{
string command = deviceSpecialArgsType.GetProperty("Command", BindingFlags.Public).GetValue(e, null).ToString();
string request = deviceSpecialArgsType.GetProperty("Request", BindingFlags.Public).GetValue(e, null).ToString();
...
}
}