doing an interface based plugin system is remarkably easy ...
a few questions though...
1) do you want to isolate the plugins ? i.e. seperate appdomains
2) are the plugins to be local or do they need to be capable of being
distributed objects ?
the simplest route for plugins providing you don't want either of the above
is just to run through an assembly getting the types ... you can then run
through the interfaces that the type supports .. supporting inheritance
chains as well is not very difficult. You would then up with a factory
method that you pass in a type to ... it would return the objects in the
assemblies you told it to look in (i.e. a subdirectory). You could also
strongly type these factories by subclassing specific plugin factories ... I
would also recommend lazy loading this info and hitting a cache the second
time through as it can be slow to get this info (esp with debug symbols).
slightly modified example (only loads plugins with attribute but loads them
for all interfaces they support) ...
public void LoadAssembly(string _AssemblyPath) {
Assembly PluginAssembly;
try {
PluginAssembly = Assembly.LoadFrom(_AssemblyPath) ;
}
catch (Exception Ex) {
throw new System.Exception("Unable to load assembly " + _AssemblyPath,
Ex) ;
}
//have assembly get all types.
System.Type [] AssemblyTypes = PluginAssembly.GetTypes() ;
Type [] Interfaces ;
foreach(Type CurrentType in AssemblyTypes) {
object [] attributes = CurrentType.GetCustomAttributes(false);
foreach(object CurAttr in attributes) {
if(CurAttr is PluginAttribute) {
Console.WriteLine("Found plugin " + CurrentType.FullName);
Console.WriteLine(((PluginAttribute)CurAttr).Name +
((PluginAttribute)CurAttr).Description);
Interfaces = CurrentType.GetInterfaces() ;
foreach(Type foo in Interfaces) {
Console.WriteLine("Interface of " + foo.ToString());
}
PluginEntry p = new PluginEntry();
p.AssemblyPath = _AssemblyPath ;
p.Type = CurrentType ;
p.Interfaces = Interfaces ;
//at this point we have all the info add it
PluginEntries.Add(p) ;
break;
}
}
}
Console.Write("Loaded " + AssemblyTypes.Length + " objects.\n");
}
Once you have the types you would just use CreateInstance to create them.
I would also recommend using an optional custom attribute on your plugins so
you can optionally give them a friendlyname, description, etc.
Example:
[AttributeUsage(AttributeTargets.Class,Inherited=false,AllowMultiple=false)]
public class PluginAttribute : Attribute {
private string m_Name;
private string m_Description;
public PluginAttribute(string _Name, string _Description) {
this.m_Name = _Name ;
this.m_Description = _Description ;
}
public string Name {
get {
return m_Name;
}
}
public string Description {
get {
return m_Description;
}
}
}
Maintaining plugins in a seperate app domain has benefits but complicates
things a bit. Let me know if you need info on that.
Hope this helps ya a bit.
Greg
Gary James said:
This may not be a direct C# question, but since I'll be using using C# for
development, I thought I'd pose the question here.
I'll soon be involved in the design of a new software product that will
employ a software "Plug-In" architecture. Taking the plug-in route will
give us a design that can adapt to, as yet, undefined future requirements
(within the scope of the plug-in interface spec of course). In the past
I've done this with COM components that register themselves in a list of
available code resources. However, I'd be interested to hear how any of
you have approached the design for a software plug-in architecture, and/or
any references you may have used to make your design decision.
Gary ...