如何获取 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();
我想创建一个基础 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();