【问题标题】:Can I get a list of assemblies that are not currently loaded我可以获得当前未加载的程序集列表吗
【发布时间】:2012-06-04 07:54:54
【问题描述】:

我想让使用我的产品的开发人员能够通过实现接口然后将程序集放入执行文件夹来扩展产品。 我应该如何寻找这些类型,我必须通过文件夹中的每个 DLL 运行还是可以避免那些属于原始应用程序的那些?

【问题讨论】:

    标签: c# reflection


    【解决方案1】:

    你为什么不使用microsoft's solutions
    据我了解,它完全可以解决您的需求

    【讨论】:

    • 我正在考虑使用 MEF,但我想要最简单的实现方式,而 MEF 的复杂性更上一层楼。
    • 我认为将它与最简单的可能性一起使用会比编写自己的依赖注入解决方案更容易添加/维护,但这当然是你的选择
    • 我还有一个不使用 MEF 的原因,那就是……底层组件是可重用的。当我开始开发它时,我希望它对任何 IoC 容器都友好,并且不依赖于特定的实现。现在我可以在应用程序中使用我的组件,如果我使用 IoC 容器,我可以使用配置来连接我的扩展。但我不太喜欢配置不变的东西,所以我想要一个替代方案,如果实现 dll 被转储到 bin 中,扩展可以自动加载。
    【解决方案2】:

    您可以将新程序集放入不同的文件夹(例如调用或插件或扩展),然后在运行时实例化它们;或者,维护产品程序集列表并使用 Path.GetFiles 并删除列表中出现的所有程序集。

    【讨论】:

    • 像什么?将扩展程序集与核心程序集分开不会让一切变得更简单、更整洁吗?
    • 您之前好像没有这样做过 :) 试试看。 (问题在于主应用程序文件夹和您的插件文件夹中的“相同”依赖项,2 个副本可以工作,但不是一个好的解决方案)。
    • 您能告诉我们问题并为我省力吗?
    • @Noel:采纳 MEF 的建议。将为您省去不少麻烦:)
    【解决方案3】:

    我将它用于用户定义的工具。

    private static void getImplementedTypes(Type baseType, Assembly assembly, IList<Type> list) {
        Type[] types = assembly.GetExportedTypes();
        foreach (Type t in types) {
            if (baseType.IsInterface) {
                Type[] interfaces = t.GetInterfaces();
                foreach (Type i in interfaces) {
                    if (i == baseType) list.Add(t);
                }
            }
            else {
                if ((!list.Contains(t)) && (t.IsSubclassOf(baseType)) && (!t.IsAbtract)) {
                    list.Add(t);
                }
            }
        }
        return n;
    }
    

    在一个循环中,我会遍历工具目录中 Directory.GetFiles 找到的所有 DLL(或 EXE):

    Assembly assembly = Assembly.LoadFile("toolbox.dll");
    List<Type> types = new List<Type>();
    getImplementedTypes(typeof(ToolBase), assembly, types);
    ToolBase theTool = Activator.CreateInstance(type, true) as ToolBase;
    

    这适用于接口和基类。

    我不知道如何以不同的方式找到已实现的类。 这可能要花点时间。因此,如果您知道要搜索哪些 DLL,只需遍历它们即可。

    【讨论】:

      【解决方案4】:

      最后,我选择简单地加载并搜索我在 bin 中找到的所有 dll。 这是大部分代码。关键函数是“IsAssignableToGenericType”函数,它可以找到我正在寻找的通用接口。

      我相信这是提供大部分解决方案的链接 Implementations of interface through Reflection

      static AssemblyLocator()
          {
              AllDlls = GetAllDlls();
              SubscribersInBin = GetSubscribersInBin();
          }
      
          public static IEnumerable<Type> TypesImplementingInterface(Assembly[] assemblies, Type desiredType)
          {
              return assemblies
                  .SelectMany(assembly => assembly.GetTypes())
                  .Where(type => IsAssignableToGenericType(type, desiredType));
          }
      
          public static bool IsAssignableToGenericType(Type givenType, Type genericType)
          {
              if (givenType == null) throw new ArgumentNullException("givenType");
              if (genericType == null) throw new ArgumentNullException("genericType");
      
              var interfaceTypes = givenType.GetInterfaces();
      
              foreach (var it in interfaceTypes)
              {
                  if (it.IsGenericType)
                  {
                      if (it.GetGenericArguments()[0].Name.Equals(genericType.GetGenericArguments()[0].Name))
                          return true;
                  }
              }
      
              Type baseType = givenType.BaseType;
              if (baseType == null) return false;
      
              return (baseType.IsGenericType &&
                  baseType.GetGenericTypeDefinition() == genericType) ||
                  IsAssignableToGenericType(baseType, genericType);
          }
      
          private static ReadOnlyCollection<string> GetAllDlls()
          {
              string binFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
              IList<string> dllFiles = Directory.GetFiles(binFolder, "*.dll", SearchOption.TopDirectoryOnly).ToList();
              return new ReadOnlyCollection<string>(dllFiles);
          }
      
          private static ReadOnlyCollection<Type> GetSubscribersInBin()
          {
              IList<Assembly> assembliesFoundInBin = new List<Assembly>();
              foreach (var item in AllDlls)
              {
                  var assembly = System.Reflection.Assembly.LoadFrom(item);
                  assembliesFoundInBin.Add(assembly);
              }
      
              var typesInBin = TypesImplementingInterface(assembliesFoundInBin.ToArray(), typeof(ISubscriber<T>));
              return new ReadOnlyCollection<Type>(typesInBin.ToList<Type>());
          }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-11-08
        • 1970-01-01
        • 2011-09-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-09-18
        • 2018-07-27
        相关资源
        最近更新 更多