Dynamic Event Handling Using Reflection

Download DynamicEvent.zip

In an article earlier, I discussed how to dynamically load an assembly and execute it via the contract of a predefined interface. The technique mentioned there was useful for writing pluggable modules. However, any non-trivial implementations of a pluggable module probably require the communication between the module and the host program (e.g. progress, status, etc). In the previous discussion, this capability was not present.

To achieve dynamic event handling, we will first modify the PlugInInterface as follows:

    public delegate void ProgressChangedDelegate(object state);

    public interface PlugInInterface

    {

        event ProgressChangedDelegate ProgressChanged;

        void Test();

    }

As shown above, an event is added to the interface (note, in VB.Net the delegate declaration is not required, the parameters can be implicitly supplied to the event ProgressChanged, e.g. Event ProgressChanged(ByVal state As Object)).

Next, I will add the event to the PlugInLib:

    public class PlugIn : PlugInInterface.PlugInInterface

    {

        private Hashtable _ht;

        public event PlugInInterface.ProgressChangedDelegate ProgressChanged;

 

        public Hashtable Hash

        {

            get {return _ht;}

            set {_ht = value;}

        }

        public PlugIn()

        {

            _ht = new Hashtable();

            _ht["Key"] = "Value";

        }

        public void Test()

        {

            if (ProgressChanged != null)

            {

                ProgressChanged("start");

            }

 

            Console.WriteLine(_ht["Key"].ToString());

 

            if (ProgressChanged != null)

            {

                ProgressChanged("done!");

            }

        }

 

The changes in the main program are a bit more complex:

    class Program

    {

        public void Test()

        {

            string path = Path.Combine(Environment.CurrentDirectory, "..\\..\\..\\PlugInLib\\bin\\debug");

            string fileName = Path.Combine(path, "PlugInLib.dll");

            Assembly asm = Assembly.LoadFrom(fileName);

            Type type = asm.GetType("PlugInLib.PlugIn");

            PlugInInterface.PlugInInterface cls = Activator.CreateInstance(type) as PlugInInterface.PlugInInterface;

 

            EventInfo eventProgressChanged = type.GetEvent("ProgressChanged");

            Type eventDelegate = eventProgressChanged.EventHandlerType;

            Delegate d = Delegate.CreateDelegate(eventDelegate, this, "OnProgressChanged");

            MethodInfo methodInfo = eventProgressChanged.GetAddMethod();

            Object[] args = new object[] {d};

            methodInfo.Invoke(cls, args);

 

            cls.Test();

        }

 

        private void OnProgressChanged(object state)

        {

            Console.WriteLine(state.ToString());

        }

 

        static void Main(string[] args)

        {

            Program p = new Program();

            p.Test();

        }

    }

To hook up the event from the dynamically loaded assembly, we first use Type.GetEvent to retrieve the EventInfo from PlugInLib.dll. Then, a delegate is created and hooked to the OnProgressChanged method within the current running assembly. Finally, methodInfo.Invoke(cls, args) links the delegates with the correctly the parameters with the event handler.

The example shown here can be downloaded here.

Be Sociable, Share!

Leave a Reply