0

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

4

4 回答 4

1

你为什么不使用微软的解决方案
据我了解,它可以解决您正在寻找的东西

于 2012-05-30T05:02:56.350 回答
0

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

于 2012-05-30T05:02:16.980 回答
0

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

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,只需遍历它们即可。

于 2012-05-30T05:29:54.173 回答
0

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

我相信这是通过反射提供接口实现的大部分解决方案的链接

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>());
    }
于 2012-07-25T05:58:22.403 回答