Introduction
Sometimes, you need to give a user of your application the chance to implement his own functions without recompiling the full application.
Background
For some projects, I needed the user to load their own implementations of an interface. These classes were used to collect and show some information in my application. The configuration was loaded by the runtime, and contained the name of the loaded and used classes.
So, it was needed to instantiate all these objects by Reflection during runtime.
Using the code
There are three projects in the .NET solution:
- LoadFromDll -> Contains the main function loading the UserLibrary.
- Interfaces -> Contains the interface used by the UserLibrary.
- UserLibrary -> Contains the implementations of the user.
The Interface project is used as a resource in the UserLibrary project. It defines the interface IUserInterface
:
public interface IUserInterface
{
String GetName();
int Funktion(int a, int b);
}
IUserInterface
is used by the implementations that are loaded at runtime. A sample of an implementation looks like:
public class UserClass1 : Interfaces.IUserInterface
{
public String GetName() { return "Add"; }
public int Funktion(int a, int b) { return a + b; }
}
In the main functions, all classes implementing IUserInterface
are collected:
private static Dictionary<String, Type> nameTypeDict = new Dictionary<string, Type>();
[...]
Assembly ass = Assembly.LoadFrom(@"UserLibrary.dll");
foreach (Type t in ass.GetExportedTypes())
{
if (t.GetInterface("IUserInterface", true)!=null)
{
Console.WriteLine("Found Type: {0}", t.Name);
nameTypeDict.Add(t.Name, t);
}
}
Now, you are able to instantiate and use the implementations only by the name of the class:
private static void ExecuteByName(String typeName, int a, int b)
{
IUserInterface o = (IUserInterface)nameTypeDict[typeName].InvokeMember(null,
BindingFlags.DeclaredOnly |
BindingFlags.Public | BindingFlags.NonPublic |
BindingFlags.Instance | BindingFlags.CreateInstance,
null, null, null);
Console.WriteLine(o.GetName());
Console.WriteLine(o.Funktion(a, b));
}
Points of interest
I use this code with a configuration file containing the assembly's file name and the order of the loaded classes.
History