Download ReflectionTest.zip
There are already many good guides out there illustrating how to construct a weakly coupled system that dynamically loads in modules as needed. In .Net, this can be accomplished using reflection.
However, some people are confused about Reflection versus Serialization, thinking that a class must be serializable before it can be dynamically loaded. This is not the case however. Reflection is typically used to reflect upon the object’s type, member information and dynamically invoke object’s methods whereas serialization is typically used to transfer objects’ states across wires.
Here I will give a very simple example to show how reflection can be used to create pluggable application architecture.
First, let’s create an interface that defines the common functionalities of our plug-ins. It is always desirable to define a common interface for all the plug-in modules as the main application that loads and executes these modules need not to have any information about the plugged in objects.
public interface PlugInInterface
{
void Test();
}
Next, we create a simple pluggable module that is based on this interface.
public class PlugIn : PlugInInterface.PlugInInterface
{
private Hashtable _ht;
public Hashtable Hash
{
get {return _ht;}
set {_ht = value;}
}
public PlugIn()
{
_ht = new Hashtable();
_ht["Key"] = "Value";
}
public void Test()
{
Console.WriteLine(_ht["Key"].ToString());
}
}
In the above example, the module does nothing but adds an entry to a hashtable. The point I want to make here is that since we will be using reflection mechanism to invoke this class, no serialization is required. In fact an hashtable cannot be simply serialized by the Serializable() attribute as XmlSerializer does not serialize objects that implement IDictionary by default (see this article on MSDN on how to get around this).
Here is the main class that loads the plugin assembly using reflection:
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;
cls.Test();
}
static void
{
Program p = new Program();
p.Test();
}
}
Since the plugin implements PlugInInterface, it is desirable to put the interface in its own class library so that we only need to make a reference to the interface class library not the actual plug-in itself.
The full example code can be downloaded here (in C#, Framework 2.0).