获取跨多个 .NET 程序集实现接口的类 [已关闭]

Get class that implements an interface across multiple .NET assemblies [closed]

提问人:Zer0 提问时间:10/1/2023 更新时间:10/1/2023 访问量:41

问:


想改进这个问题吗?通过编辑这篇文章添加详细信息并澄清问题。

上个月关闭。

我一直在尝试找到实现某个接口的所有类。我以前从未进行过任何形式的反思,所以我对此有点陌生。话虽如此,我已经根据一堆文章和堆栈溢出帖子实施了几种方法,但仍然无法让它工作。

问题是我似乎找不到在 中实现跨多个程序集的接口的类。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
   }
}

这已经是我的问题了,在我的第一次测试中,我得到了正确的接口名称。 但是在第二个测试用例中,我得到了我所期望的.ILoadingfalsetrue

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

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

有没有人知道为什么找不到这个类?TestLoading

C# 程序集

评论

0赞 Jonathan Dodds 10/1/2023
你想达到什么目的?您是否正在重塑 MEFDI?
0赞 Alexei Levenkov 10/1/2023
通常问题在于使用了错误的类型......不幸的是,如果没有一个真正最小的可重现示例,就不可能弄清楚你在哪里复制粘贴了一个接口,而不是引用一个接口。请使用精心制作(和测试)的示例代码来编辑问题,用于两个涉及的程序集。请注意,加载“AssemblyB”是完全不必要的,因为您的主代码应该已经为代码加载了它 - 您的代码示例不需要 LoadFrom 行(显然您可能会误导读者来自哪里......但这样想是不礼貌的)。typeof(ILoading)ILoading

答:

0赞 iSR5 10/1/2023 #1

您需要加载当前程序集,然后获取其位置和名称。然后,在目录中搜索(从给定位置)的所有文件,并使用以程序集名称开头的文件筛选搜索(如果所有类型都位于具有不同命名空间的同一程序集下,例如 (Project、Project.Core、Project.Something ..等)。.dll

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

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。