在 C# 中使用反射添加和删除异步事件处理程序

Add and remove async event handlers using reflection in c#

我有以下实际有效的代码示例:

namespace DeviceLib
{
    public interface IInstrument
    {
        event Action<InstrumentConnectionStatus> OnConnectionChanged;
        event Action OnRemoteMeasureRequested;
    }

public class InstrumentInstance
{
    public delegate Task EventCompletedHandler(object sender, dynamic eventArgs);
    public event EventCompletedHandler StatusChanged = async delegate { };
    public event EventCompletedHandler RemoteMeasureRequested = async delegate { };
    IInstrument Instrument;

    public InstrumentInstance(string DriverName)
    {
        Instrument = DriverName switch
        {
            Instrument1.DRIVER => new Instrument1Driver(),
            instrument2.DRIVER => new Instrument2Driver(),
            _ => throw new NotSupportedException($"Driver {DriverName} not supported"),
        };
    }

    public async Task<object> OnStatusChanged()
    {
        Instrument.OnConnectionChanged += async (InstrumentConnectionStatus status) =>
        {
            await StatusChanged(nameof(OnStatusChanged), status.ToString());
        };

        return null;
    }

    public async Task<object> OnRemoteMeasureRequested()
    {
        Instrument.OnRemoteMeasureRequested += async () =>
        {
            await RemoteMeasureRequested(nameof(OnRemoteMeasureRequested), null);
        };

        return null;
    }
}

}

namespace DeviceConsumer 
{
    public class InstrumentService
    {
        static Type Type = typeof(DeviceLib.InstrumentInstance);
        DeviceLib.InstrumentInstance InstrumentInstance;
        static List<MethodInfo> AvailableEventHandlers =  Type.GetMethods().Where(x => x.DeclaringType == Type && !x.IsSpecialName && x.Name.StartsWith("On")).ToList();
        static List<EventInfo> AvailableEvents=Type.GetEvents().ToList();
    

        public InstrumentService()
        {

        }

        public async Task CreateInstrumentInstance(string driverName)
        {
            this.InstrumentInstance = new DeviceLib.InstrumentInstance(driverName);
        
        
            // Invoking the methods that wrap the event handlers with reflection
            foreach (MethodInfo eventHandler in AvailableEventHandlers)
                await (Task<object>)eventHandler.Invoke(InstrumentInstance, new object[] { });


            InstrumentInstance.StatusChanged +=  async(s,e) => await ProcessInstrumentEvent(s,e);
            InstrumentInstance.RemoteMeasureRequested += async (s, e) => await ProcessInstrumentEvent(s, e);
        }

        private async Task ProcessInstrumentEvent(object sender, dynamic eventArgs)
        {
            await Task.Run(() =>
            {
                Console.Write($"Event {sender} Fired!");
            });
        }

}

 

现在我想将与事件关联的静态部分替换为 ProcessInstrumentEvent 方法:

InstrumentInstance.StatusChanged +=  async(s,e) => await ProcessInstrumentEvent(s,e);
InstrumentInstance.RemoteMeasureRequested += async (s, e) => await ProcessInstrumentEvent(s, e);

类似的东西:

        foreach (EventInfo ev in AvailableEvents)
        {
           // EventHandler handler = async delegate (object s, dynamic e) { await ProcessInstrumentEvent(s, e); };
          
           //  EventHandler handler = new EventHandler(async (s, e) => await ProcessInstrumentEvent(s,e));


             ev.AddEventHandler(InstrumentInstance, handler);

        }

None 两种定义“处理程序”的方法都有效,我在这里失败了吗?我想我非常接近,这个实现的目标是动态添加(然后删除)在 class “InstrumentService” 中以方法“ProcessInstrumentEvent”为目标的处理程序,因此不使用 += 和 -= 运算符,所以我认为我可以使用反射方法“AddEventHandler”和“RemoveEventHandler”来实现这一点

这应该有效:

var obj = new InstrumentInstance("foo");

EventCompletedHandler handler = async (s, e) => await ProcessInstrumentEvent(s, e);

foreach (var evt in obj.GetType().GetEvents(BindingFlags.Public | BindingFlags.Instance))
{
    if (evt.EventHandlerType == typeof(EventCompletedHandler))
    {
        Console.WriteLine($"Binding '{evt.Name}'");
        evt.AddEventHandler(obj, handler);
    }
}

它也应该在没有额外间接寻址的情况下工作:

EventCompletedHandler handler = ProcessInstrumentEvent;