lundi 29 novembre 2021

Dynamic execution of methods and registration of event handlers with reflection in c#

I have a series of instruments with different implementations that share the same IInstrument interface, the instantation was made in this way:

public async Task<object> CreateInstrumentDriver(dynamic input)
    {
        IInstrument instrument = ((string)input.Name) switch
        {
            InstrumentA.DRIVER => new InstrumentADriver(),
            InstrumentB.DRIVER => new InstrumentBDriver(),
            InstrumentC.DRIVER => new InstrumentCDriver(),
            _ => throw new NotSupportedException($"{input.driverName} is not supported"),
        };

        return new
        {
            connect = (Func<object, Task<object>>)(
                async (dynamic arg) =>
                {
                    var info = new InstrumentConnectionInfo
                    {
                        Id = (string)arg.id,
                        Name = (string)arg.name
                    };

                    InstrumentDescriptor descriptor = await instrument.Connect(info);

                    return descriptor.CovertToJSONObject();
                }
            ),
            disconnect = (Func<object, Task<object>>)(
                async (dynamic arg) =>
                {
                    await instrument.Disconnect();
                    return null;
                }
            ),
            calibrate = (Func<object, Task<object>>)(
                async (dynamic arg) =>
                {
                    return await instrument.Calibrate();
                }
            ),
            measure = (Func<object, Task<object>>)(
                async (dynamic arg) =>
                {
                    Measurement measurement = await instrument.Measure();
                    return measurement.CovertToJSONObject();
                }
            ),
            status = (Func<object, Task<object>>)(
                async (dynamic arg) =>
                {
                    return instrument.ConnectionStatus;
                }
            ),
            descriptor = (Func<object, Task<object>>)(
                async (dynamic arg) =>
                {
                    return instrument.Descriptor;
                }
            ),
            onStatusChanged = (Func<object, Task<object>>)(
                async (dynamic arg) =>
                {
                    instrument.OnConnectionChanged += (InstrumentConnectionStatus status) =>
                    {
                        ((Func<object, Task<object>>)arg.handler)(status);
                    };

                    return null;
                }
            ),
            onRemoteMeasureRequested = (Func<object, Task<object>>)(
                async (dynamic arg) =>
                {
                    instrument.OnRemoteMeasureRequested += () =>
                    {
                        ((Func<object, Task<object>>)arg.handler)(null);
                    };

                    return null;
                }
             ),
            onRemoteMeasurementResult = (Func<object, Task<object>>)(
                async (dynamic arg) =>
                {
                    instrument.OnRemoteMeasurementResult += (Measurement measurement, InstrumentRemoteMeasurementStatus status, string message) =>
                    {
                        ((Func<object, Task<object>>)arg.handler)(new { measurement, status, message }.CovertToJSONObject());
                    };

                    return null;
                }
             )
        };
    }

Now I'm calling the instrument instance with this code and it's OK, the object MyInstance is populated correctly with all methods and events of DeviceA and I can persist it somewhere for future use:

var instrumentInstance = new DeviceLib.Startup();
object MyInstance = await instrumentInstance.CreateInstrumentDriver(new InstrumentConnectionInfo { Name = "DeviceA" });

Now the dumb question, since I've not written the CreateInstrumentDriver method (which I admit I din't fully understood the syntax) but in some way I have to call it from another project (where the dll that contains the methos is linked of course) how I can, (I imagine using Reflection) invoke the various functions (connect, calibrate, measure...) and register the event handlers (onStatusChanged, onRemoteMeasureRequested... ) possibly in a dynamic way so, for example if I have in input a string variable with the value "connect" I can invoke the method "connect" (with its parameters), in brief I need a sort of a dynamic Execute(string command, dynamic params) method and a way for dynamically handling the events generated by the instrument so I can execute some code when they have been triggered





Aucun commentaire:

Enregistrer un commentaire