如何获取 classes 的列表,从一个 class 和一个接口/或从两个接口继承

How to get List of classes, inheriting from one class and one interface / or instead from two interfaces

我想创建一个基础 class 的默认后代实例列表。我已经可以得到的是这些后代的 List<Type>IEnumerable<Type>

基地class及后代均为自制。所以我很理解他们。

C# Framework 是否已经为此提供了一种智能方式?

这是我得到的:

    public static List<Type> GetList_Descendants(Type baseClassType, string assemblyName)
    {
        return Assembly
        .GetAssembly(baseClassType)
        .GetTypes()
        .Where(t => t.IsSubclassOf(baseClassType))
        .ToList(); // Otherwise return would be of type IEnumerable.
    }

    public static void Add_AllDescendants<T>(this List<T> emptySource, List<Type> descendants)
        where T : new()
    {
        emptySource.AddRange(???);
    }

class && 接口的后代

stop-cran 已经给了我一个答案,关于如何获得泛型类型给出的 class 的后代。 (请参阅下面的第一个答案和前两条评论。)


两个接口的后代

如何获取两个接口的后代? 这就是我所做的,它的工作原理:

    /// <summary>
    /// Assumes, that there are two interfaces and classes inheriting of both - all placed in the same assembly.
    /// 1st interface is IStrategy. 2nd interface is described by generic type.
    /// 
    /// Creates an IEnumerable of all available Func'IStrategy' child instances which are of generic type, too.
    /// Thus one decouple creation of such a IEnumerable from creating the child classes of type IStrategy.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public static IEnumerable<Func<IStrategy>> GetByInterfaceBaseType<T>() =>
    typeof(T)
    .Module
    .Assembly
    .GetTypes()
    .Where(t => (t.GetInterface(typeof(T).FullName)!= null)
             && (t.GetInterface(nameof(IStrategy)) != null))
    // We assume T has a parameterless constructor
    .Select(t => (Func<IStrategy>)(() => (IStrategy)Activator.CreateInstance(t)));

这是一个 link,您可能也会感兴趣: List all classes that inherit from a specific class/interface

对我来说,这个案子已经解决了。但总是欢迎好的建议!

考虑到问题评论,我建议有一个 IStrategy 接口并使用 IEnumerable<Func<IStrategy>> 来注入策略工厂列表(这里为了简洁我使用委托工厂,可以使用一个接口)。因此,将创建这样一个列表与创建策略分离开来:

static IEnumerable<IStrategy> CreateAll(this IEnumerable<Func<IStrategy>> factories) =>
    factories.Select(factory => factory());

示例用法:

listOfStrategies.AddRange(
    new Func<IStrategy>[]
    {
        () => new B(),
        () => new C()
    }).CreateAll()); // 2 items (`B` and `C`) will be added.

如果方便的话,可以从 class 层次结构中创建策略工厂列表 (Func<IStrategy>):

static IEnumerable<Func<IStrategy>> GetByBaseType<T>() =>
    typeof(T)
        .Assembly
        .GetTypes()
        .Where(t => t.IsSubclassOf(typeof(T)) && t.GetInterface(nameof(IStrategy)) != null)
        // We assume t has a parameterless constructor
        .Select(t => (Func<IStrategy>)(() => (IStrategy)Activator.CreateInstance(t)));

样本:

class A { }

class B : A, IStrategy { }

class C : A, IStrategy { }

创建策略工厂列表:

var factories = GetByBaseType<A>().ToList(); // Two `Func<IStrategy>` objects
var strategies = CreateAll(factories).ToList(); // Two `IStrategy` objects - `B` and `C`.

还有一个 returns IEnumerable<T> 的方法通常比采用 List<T> 并向其中添加项目的方法更可重用和 "pure"。

还有一件事 - 许多 DI 容器支持解析所有已注册实现的列表。请参阅下面的 UnityContainer 示例:

var c = new UnityContainer()
    .RegisterType<IStrategy, B>("B")
    .RegisterType<IStrategy, C>("C");

// Two items - `B` and `C`.
c.Resolve<IEnumerable<IStrategy>>().ToList();