繁体   English   中英

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

[英]Retrieve a list of object implementing a given interface

介绍

我正在我的应用程序中构建插件架构。 插件实现给定的接口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)

你有关于如何实现这个的建议吗?

你可以尝试这样的事情:

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

我在比赛系统中使用了类似的方法。

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

在trunk / TournamentApi / Plugins / PluginLoader.cs中,我已经定义了加载任意程序集插件所需的方法。


我使用的想法是一个Plugin-Factory-Enumerator类,可以找到,实例化并调用它来生成插件工厂实例。

这是代码的内容:

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();

我会使用IOC容器来执行插件查找。 MEF可能有点多,但StructureMap是一个单独的DLL,内置支持开箱即用。

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

在ObjectFactory的Configure方法中扫描的示例:

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

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

            scanner.With(typeScanner);
        });

类型扫描程序实现ITypeScanner,并且可以检查类型是否检查类型是否可分配给相关的接口类型。 附带的文档链接中有很好的示例。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM