2009-10-13 40 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和可以檢查類型檢查,如果類型是分配給所討論的接口類型。在附上的文檔鏈接中有很好的例子。