Search code examples
c#reflectionprismeventaggregator

Can I use reflection on Prism's EventAggregator?


I am trying to refactor some of my methods in the PRISM framework, and it's not really working out.

I need to publish messages through the EventAggregator, and I have written a reflection method which will look through a List<Parameters> containing Types and from here send the messages. But it never sends any messages.

It turns out the safecast as PubSubEvent<object> is not the same as public class Input: PubSubEvent<Output> {}, which means the returnObj?.Publish(data); is null and will not be called.

public struct Parameters
{
    public string Topic;
    public Type Input;
    public Type Output;
}


private List<Parameters> _list;
...
void SomeFunction()
{
    _list.ForEach(m =>
    {
        var data = JsonConvert.DeserializeObject(dataString, m.Output);

        var eventAggType = _eventAggregator.GetType();
        var eventMethod = eventAggType.GetMethod("GetEvent");
        var genericMethod = eventMethod.MakeGenericMethod(m.Input);
        var returnObj = genericMethod.Invoke(_eventAggregator, null) as PubSubEvent<object>;
        returnObj?.Publish(data);

        // var datType = returnObj.GetType();
        // if (datType.BaseType.Name == typeof (PubSubEvent<object>).Name)
        // {
        //  var obj = Convert.ChangeType(returnObj, datType);
        //  ((PubSubEvent<object>) obj).Publish(data);
        // }
    }
}

I tried to modify the code by looking at the type it actually outputs (remove the as PubSubEvent<object>), and it's the same BaseType. But the casting to a basic PubSubEvent is not something the program is happy about.

Exception thrown: 'System.InvalidCastException' in MyProject.ModuleA.dll

EXCEPTION: Unable to cast object of type 'MyProject.ModuleA.GlobalEvents.EventA' to type 'Microsoft.Practices.Prism.PubSubEvents.PubSubEvent`1[System.Object]'.

How do I Publish with the correct type? It should look like the following, if you knew what classes you were handling:

_eventAggregator.GetEvent<EventA>().Publish(data);

Solution

  • Silly me. It's reflection - with more reflection!

    void SomeFunction()
    {
        _list.ForEach(m =>
        {
            //Deserialize the data
            var data = JsonConvert.DeserializeObject(dataString, m.Output);
    
            //Obtain the object from the EventAggregator
            var eventAggType = _eventAggregator.GetType();
            var eventMethod = eventAggType.GetMethod("GetEvent");
            var genericMethod = eventMethod.MakeGenericMethod(m.Input);
            var returnObj = genericMethod.Invoke(_eventAggregator, null);
    
            //Publish the data
            var publishMethod = returnObj.GetType().GetMethod("Publish");
            publishMethod.Invoke(returnObj, new[] {data});
        });
    }
    

    So you take the reflection, returnObj, and reflect the function Publish(...) and Invoke it from your reflected object, returnObj, with the data parameter.