通过反射附加事件处理程序

本文关键字:事件处理 程序 反射 | 更新日期: 2023-09-27 17:51:00

我有以下代码:

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:'Temp'Device.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:'Temp'Device.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();
        ...
    }
}