Если вы не хотите использовать MEF, попробуйте это.
Прежде всего определите (в библиотеке) ваши интерфейсы:
namespace Interfaces
{
public interface IPlugin01
{
string Name { get; }
string Description { get; }
void Calc1();
}
public interface IPlugin02
{
void Calc2();
}
}
Затем напишите ваши плагины (вероятно, сборки в файлах DLL), используя классы, реализующие ваши интерфейсы (один или несколько):
namespace Plugin01
{
public class Class1 : Interfaces.IPlugin01,Interfaces.IPlugin02
{
public string Name { get { return "Plugin01.Class1"; } }
public string Description { get { return "Plugin01.Class1 description"; } }
public void Calc1() { Console.WriteLine("sono Plugin01.Class1 Calc1()"); }
public void Calc2() { Console.WriteLine("sono Plugin01.Class1 Calc2()"); }
}
public class Class2 : Interfaces.IPlugin01
{
public string Name { get { return "Plugin01.Class2"; } }
public string Description { get { return "Plugin01.Class2 description"; } }
public void Calc1() { Console.WriteLine("sono Plugin01.Class2 Calc1()"); }
}
}
Наконец, создайте ваше приложение, которое загружает и использует ваши плагины:
namespace Test
{
class Program
{
/// ------------------------------------------------------------------------------
/// IMPORTANT:
/// you MUST exclude Interfaces.dll from being copied in Plugins directory,
/// otherwise plugins will use that and they're not recognized as using
/// the same IPlugin interface used in main code.
/// ------------------------------------------------------------------------------
static void Main(string[] args)
{
List<Interfaces.IPlugin01> list1 = new List<Interfaces.IPlugin01>();
List<Interfaces.IPlugin01> list2 = new List<Interfaces.IPlugin01>();
List<Interfaces.IPlugin01> listtot = GetDirectoryPlugins<Interfaces.IPlugin01>(@".\Plugins\");
Console.WriteLine("--- 001 ---");
foreach(Interfaces.IPlugin01 plugin in list1)
plugin.Calc1();
Console.WriteLine("--- 002 ---");
foreach (Interfaces.IPlugin01 plugin in list2)
plugin.Calc1();
Console.WriteLine("--- TOT ---");
foreach (Interfaces.IPlugin01 plugin in listtot)
plugin.Calc1();
Console.ReadLine();
}
public static List<T> GetFilePlugins<T>(string filename)
{
List<T> ret = new List<T>();
if (File.Exists(filename))
{
Assembly ass = Assembly.LoadFrom(filename);
foreach (Type type in ass.GetTypes())
{
if (!type.IsClass || type.IsNotPublic) continue;
if (typeof(T).IsAssignableFrom(type))
{
T plugin = (T)Activator.CreateInstance(type);
ret.Add(plugin);
}
}
}
return ret;
}
public static List<T> GetDirectoryPlugins<T>(string dirname)
{
/// To avoid that plugins use Interfaces.dll in their directory,
/// I delete the file before searching for plugins.
/// Not elegant perhaps, but functional.
string idll = Path.Combine(dirname, "Interfaces.dll");
if (File.Exists(idll)) File.Delete(idll);
List<T> ret = new List<T>();
string[] dlls = Directory.GetFiles(dirname, "*.dll");
foreach (string dll in dlls)
{
List<T> dll_plugins = GetFilePlugins<T>(Path.GetFullPath(dll));
ret.AddRange(dll_plugins);
}
return ret;
}
}
Просто комментарий: мои решения (содержащие интерфейсы, плагины и приложение консоли тестирования) скомпилировали мое приложение в . \ Bin , а плагины в . \ Bin \ Plugins . В обеих папках был развернут Interfaces.dll , на который опираются мои проекты. Это серьезная проблема , помните (читайте комментарии в коде) !!!
Таким образом, вы можете скомпилировать свои плагины, избегая, чтобы Interfaces.dll копировался в . \ Bin \ Plugins dir; но если вы забудете это, ваше приложение не будет работать вообще; поэтому я решил принудительно удалить DLL перед поиском и загрузкой плагинов.