I don't know why you want to use the assembly (assembly, not "DLL") loaded during runtime, but you may have your reasons.
You are doing it in a bad way from the very beginning. Look at your code using reflection. It relies on hard-coded
magic words the strings "Test", "Startup", "AfterSessionComplete", and the like.
This is unsupportable and extremely unreliable. The compiler won't warn you if you misspell any of these magic words, and what if you decide to change some of the names? So, this is rubbish which belongs to a dumpster.
The reflection problem without hard-coding can be simply resolved. For example, you could create some interface known to both host application assembly and the plug-in assembly. It could be declared in some library assembly, but you can even declare it in your host application assembly. The plug-in assembly can statically reference the host application assembly (yes, despite of one of the common misconception "EXE" assembly can also be referenced; in .NET, distinction between "EXE" and "DLL" is not essential). It would not create any circular dependencies.
You can always use some event declaration in your interface. Only
TestStateHandler
type is not so good. The mainstream way of defining event instance type is this: first define event arguments type derived from
System.EventArgs
and then use it in generic
System.EventHandler
:
public class MyEventArgs : System.EventArgs {}
public interface IMyPlugin {
public static event System.EventHandler<MyEventArgs> AfterTestComplete;
}
But, in principle, you can use your
TestStateHandler
, if you really want it, but I don't see why…
Now what? In the host application, you need to find some type which implements this interface. How? This is the simplest way:
https://msdn.microsoft.com/en-us/library/system.type.isassignablefrom%28v=vs.110%29.aspx[
^].
If more than one type implements this interface, do… whatever you want, say, use the first one, or deny the whole assembly as wrong one. I go further and define a special assembly-level attribute which claims that certain type(s) implement certain plug-in interface(s), and then I don't have to traverse all the type, but have to check up this claim during runtime. You can find further detail in my past answers:
Access a custom object that resides in plug in dll[
^],
Gathering types from assemblies by it's string representation[
^],
C# Reflection InvokeMember on existing instance[
^],
Dynamically Load User Controls[
^].
At the end of your reflection work, you instantiate the desired class which, as you found, implements the interface you want. For instantiation, you either use
Activator.CreateInstance(Type)
, or use
MethodInfo.Invoke
on a constructor. So, you can safely type-cast the type reference to the interface reference:
IMyPlugin plugin = (IMyPlugin)instantiatedType;
From this point, you can use the object reference
plugin
to add your event handler to the invocation list of the event instance in question, or do whatever else you need to do with this object, as you would do with any instance of any statically known type.
—SA