2009-10-13 42 views
1

介绍检索对象的列表,实现给定的接口

我建立我的应用程序插件架构。插件实现给定的接口IBasePlugin,或一些其它接口,其从所述基部接口继承:

interface IBasePlugin 
interface IMainFormEvents : IBasePlugin 

主机加载插件组件,然后创建任何类的适当的对象执行IBasePlugin接口..

这是类加载插件和实例的对象:

public class PluginCore 
{ 
    #region implement singletone instance of class 
    private static PluginCore instance; 
    public static PluginCore PluginCoreSingleton 
    { 
     get 
     { 
      if (instance == null) 
      { 
       instance = new PluginCore(); 
      } 
      return instance; 
     } 
    } 
    #endregion 

    private List<Assembly> _PlugInAssemblies = null; 
    /// <summary> 
    /// Gets the plug in assemblies. 
    /// </summary> 
    /// <value>The plug in assemblies.</value> 
    public List<Assembly> PlugInAssemblies 
    { 
     get 
     { 
      if (_PlugInAssemblies != null) return _PlugInAssemblies; 

      // Load Plug-In Assemblies 
      DirectoryInfo dInfo = new DirectoryInfo(
       Path.Combine(
        Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), 
        "Plugins" 
        ) 
       ); 
      FileInfo[] files = dInfo.GetFiles("*.dll"); 
      _PlugInAssemblies = new List<Assembly>(); 
      if (null != files) 
      { 
       foreach (FileInfo file in files) 
       { 
        _PlugInAssemblies.Add(Assembly.LoadFile(file.FullName)); 
       } 
      } 

      return _PlugInAssemblies; 
     } 
    } 

    List<IBasePlugin> _pluginsList = null; 
    /// <summary> 
    /// Gets the plug ins instances. 
    /// all the plugins are being instanciated ONCE when this if called for the first time 
    /// every other call will return the existing classes. 
    /// </summary> 
    /// <value>The plug ins instances.</value> 
    public List<IBasePlugin> PlugInInstances 
    { 
     get 
     { 
      if (_pluginsList != null) return _pluginsList; 

      List<Type> availableTypes = new List<Type>(); 

      foreach (Assembly currentAssembly in this.PlugInAssemblies) 
       availableTypes.AddRange(currentAssembly.GetTypes()); 

      // get a list of objects that implement the IBasePlugin 
      List<Type> pluginsList = availableTypes.FindAll(delegate(Type t) 
      { 
       List<Type> interfaceTypes = new List<Type>(t.GetInterfaces()); 
       return interfaceTypes.Contains(typeof(IBasePlugin)); 
      }); 

      // convert the list of Objects to an instantiated list of IBasePlugin 
      _pluginsList = pluginsList.ConvertAll<IBasePlugin>(delegate(Type t) { return Activator.CreateInstance(t) as IBasePlugin; }); 

      return _pluginsList; 
     } 
    } 

问题

目前,它支持任何插件模块,采用PlugInInstances属性检索IBasePlugins名单。然后它迭代查询谁在实现给定子接口的对象。

foreach (IBasePlugin plugin in PluginCore.PluginCoreSingleton.PlugInInstances) 
{ 
    if (plugin is IMainFormEvents) 
    { 
     // Do something 
    } 
} 

我想通过接收给定子接口的函数来改进这种技术,并返回这些接口的列表。问题是调用者不应该执行任何投射。

伪代码:

void GetListByInterface(Type InterfaceType, out List<InterfaceType> Plugins) 

你有一个建议,如何实现这一点?

+4

您是否考虑过使用Microsoft的Managed Extensibility Framework? //www.codeplex.com/MEF – TrueWill 2009-10-13 22:29:14

+0

@TrueWill:我会研究它 – Amirshk 2009-10-13 22:33:34

+0

@TrueWill:我的代码完全在家里做。我会在几个小时后看看。 – 2009-10-13 22:45:07

回答

2

你可以尝试这样的事:

void GetListByInterface<TInterface>(out IList<TInterface> plugins) where TInterface : IBasePlugin 
{ 
    plugins = (from p in _allPlugins where p is TInterface select (TInterface)p).ToList(); 
} 
+0

@Andrew:谢谢,就是我在找的东西。虽然我必须在没有LINQ的情况下实现它,因为我已经符合.NET 2。 – Amirshk 2009-10-13 23:24:47

+0

我应该说_allPlugins.OfType ()但它并不重要,因为你不使用LINQ。 – 2009-10-15 21:47:33

2

我用我的赛制类似的方法。

您可以在这里的源看看: http://tournaments.codeplex.com/SourceControl/ListDownloadableCommits.aspx

在树干/ TournamentApi /插件/ PluginLoader.cs,我已经定义加载任意组装的插件所需的方法。


我以前的想法是,可以发现,实例化,并呼吁生产厂家插件实例一个插件,工厂枚举类。

这里是代码的肉:

List<IPluginFactory> factories = new List<IPluginFactory>(); 

try 
{ 
    foreach (Type type in assembly.GetTypes()) 
    { 
     IPluginEnumerator instance = null; 

     if (type.GetInterface("IPluginEnumerator") != null) 
     { 
      instance = (IPluginEnumerator)Activator.CreateInstance(type); 
     } 

     if (instance != null) 
     { 
      factories.AddRange(instance.EnumerateFactories()); 
     } 
    } 
} 
catch (SecurityException ex) 
{ 
    throw new LoadPluginsFailureException("Loading of plugins failed. Check the inner exception for more details.", ex); 
} 
catch (ReflectionTypeLoadException ex) 
{ 
    throw new LoadPluginsFailureException("Loading of plugins failed. Check the inner exception for more details.", ex); 
} 

return factories.AsReadOnly(); 
0

我将使用IoC容器进行插件查找。 MEF可能稍微有点多,但StructureMap是一个单独的DLL,并且已经内置了对这个框的支持。

您可以扫描包含实现接口的对象的程序集文件夹,并将它们轻松加载到应用程序中。 StructureMap on SourceForge

的ObjectFactory的配置方法中扫描的实施例:

 Scan(scanner => 
     { 
      string assemblyPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); 

      scanner.AssembliesFromPath(assemblyPath, assembly => { return assembly.GetName().Name.StartsWith("Plugin."); }); 

      scanner.With(typeScanner); 
     }); 

该类型的扫描仪实现ITypeScanner和可以检查类型检查,如果类型是分配给所讨论的接口类型。在附上的文档链接中有很好的例子。