获取跨多个 .NET 程序集实现接口的类

问题描述 投票:0回答:1

我一直在尝试查找所有实现某个接口的类。我以前从未接触过任何类型的反思,所以我对此还很陌生。话虽如此,我已经根据一堆文章和堆栈溢出帖子实现了几种方法,但仍然无法使其工作。

问题是我似乎找不到在.NET6中跨多个程序集实现接口的类。

为了给您提供一些背景信息,我当前的测试实现很好地总结了问题。

注意:如果程序集之间的引用很重要,则 AssemblyA -> AssemblyB、AssemblyC -> AssemblyB

//Assembly A
public class SomeFunnyClass 
{
   public static void Main(string[] args)
   {
      Assembly.LoadFrom("AssemblyB.dll");
      Assembly assemblyC = Assembly.LoadFrom("AssemblyC.dll");
      SomeTests(assemblyC);
   }


   public void SomeTests(Assembly assembly) 
   {
      var test = assembly.GetType("TestLoading").GetInterfaces(); // ILoading

      var test2 = typeof(ILoading).IsAssignableFrom(assembly.GetType("TestLoading")); // false
   }
}

这已经是我的问题了,在我的第一次测试中,我得到了正确的接口名称

ILoading
。 但在第二个测试用例中,我得到了
false
,我希望是
true

// Assembly B
public interface ILoading 
{
   void OnLoad();
}
// Assembly C
public class TestLoading : ILoading 
{
    public void OnLoad(){
       // Do some cool stuff here
    }
}

我已经尝试了几种不同的方法,但最终总是得到相同的结果。我还确保加载了所有必需的程序集。

有人知道为什么找不到

TestLoading
类吗?

c# assemblies
1个回答
0
投票

您需要加载当前程序集,然后获取其位置和名称。然后,您(从给定位置)搜索目录中的所有

.dll
并使用以程序集名称开头的文件过滤搜索(如果您的所有类型都位于具有不同命名空间的同一程序集下,例如 (Project, Project.核心、项目..等)。

这是我从我的一个旧项目中获得的工作代码,它将帮助您理解逻辑。该类只会加载以当前程序集名称开头的程序集,并缓存类型,因此可以重用它,而无需再次重新加载程序集。

public static class TypeLoader
{
    private static Type[] _loadedTypes;

    private static IEnumerable<Type> GetLoadedTypes()
    {
        var assembly = Assembly.GetExecutingAssembly();

        var location = assembly.Location;

        var folder = location[..location.LastIndexOf('\\')];

        var assemblyName = assembly.GetName().Name;

        var index = assemblyName.IndexOf('.');

        var offset = index == -1 ? assemblyName.Length : index;

        var searchPattern = string.Format("{0}*.dll", assemblyName.Substring(0, offset));

        foreach (var file in Directory.GetFiles(folder, searchPattern))
        {
            foreach (var type in Assembly.LoadFrom(file).GetTypes())
            {
                yield return type;
            }
        }
    }   

    public static IEnumerable<T> GetInstances<T>() where T : class
    {
        if(_loadedTypes == null)
            _loadedTypes = GetLoadedTypes().ToArray();

        
        foreach (var type in _loadedTypes.Where(x => (x.IsSubclassOf(typeof(T)) || typeof(T).IsAssignableFrom(x)) && x.IsClass && !x.IsAbstract))
        {
            yield return Activator.CreateInstance(type) as T;
        }
    }
}

请注意,如果您使用 .NET5+,则应避免此类工作,而应使用 DI。

© www.soinside.com 2019 - 2024. All rights reserved.