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

时间:2014-03-18 22:32:07

标签: c# reflection event-handling .net-3.5 c#-3.0

我有以下代码:

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);
    }   
}

如何使用反射订阅活动?另外,我应该如何对处理程序本身进行原型化,因为&#34; args&#34;在编译时是未知的?仅供参考,我是C#3和.NET 3.5。

1 个答案:

答案 0 :(得分:1)

首先,看看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);

编辑:如果您无法控制正在加载的程序集,请尝试以下代码。它只是使用第二个参数的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();
        ...
    }
}