I have the following code sample that actually works:
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!");
});
}
}
Now I want to substitute the static part that associates the events to the ProcessInstrumentEvent method:
InstrumentInstance.StatusChanged = async(s,e) => await ProcessInstrumentEvent(s,e);
InstrumentInstance.RemoteMeasureRequested = async (s, e) => await ProcessInstrumentEvent(s, e);
With something like:
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 of the 2 approaches to define "handler" worked, where I'm failing here? I think I'm very close, the goal of this implementation is to dynamically add (and later remove) the handlers that target the method "ProcessInstrumentEvent" in class "InstrumentService" so without using = and -= operators, so I thought that I could achieve that using the reflection methods "AddEventHandler" and "RemoveEventHandler"
CodePudding user response:
This should work:
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);
}
}
It should also work without the extra indirection:
EventCompletedHandler handler = ProcessInstrumentEvent;