无法将子类对象放入列表中
本文关键字:列表 对象 子类 | 更新日期: 2023-09-27 18:18:43
您能帮我编写一个创建对象列表的方法吗?
- 我有一个类有3个子类。
- 我创建了一个方法,将所有子类放入列表中。
- 现在我在创建包含对象的列表时遇到了问题-从步骤2中每个子类一个。
- 请注意,列表应该有父类的类类型,因为它会多态引用子类的对象。
澄清:我想要一个类似于
的列表List<Class01> list = new List<Class01>();
list.Add(new SubClass0101());
list.Add(new SubClass0102());
list.Add(new SubClass0103());
,但它必须自动增长,如果子类的数量增加。
问题:我需要帮助private static IEnumerable<Type> PopulateListWithObjects<TClass>()
请参阅下面的代码以获取更多详细信息。
using System;
using System.Collections.Generic;
using System.Linq;
namespace PutObjectsInList
{
class Program
{
static void Main(string[] args)
{
// Puts all subclasses of Class01 into the list
var listOfSubClasses = SubClasses<Class01>();
// Verifies that listOfSubClasses is populated with the subclasses names
foreach (var listOfSubClass in listOfSubClasses) {Console.WriteLine(listOfSubClass);}
var listWithObjects = PopulateListWithObjects<Class01>();
}
//
private static IEnumerable<TClass> PopulateListWithObjects<TClass>()
{
var listWithObjects = new List<TClass>();
// Need help with the procedure which would populate list with the
// objects of the subclasses of the parent Class01
return listWithObjects;
}
// Enumerates all subclasses for the specified class
private static IEnumerable<Type> SubClasses<TClass>()
{
var subclasses =
(from assembly in AppDomain.CurrentDomain.GetAssemblies()
from type in assembly.GetTypes()
where type.IsSubclassOf(typeof(TClass))
select type).ToList();
return subclasses;
}
}
public class Class01 {}
public class SubClass0101 : Class01 {}
public class SubClass0102 : Class01 {}
public class SubClass0103 : Class01 {}
}
如果你想达到预期的结果,你的private static IEnumerable<Type> PopulateListWithObjects<TClass>
应该有IEnumerable<TClass>
的返回类型。
因为Type
表示的不是某种类型的对象,而是它们的类型元数据标识符System.Type
。
对于实例的创建(实例化),您可以使用Activator.CreateInstance()方法。
最后看起来像:
private static IEnumerable<TClass> PopulateListWithObjects<TClass>()
{
return ReflectorHelper.GetAndActivateAllAssignableTo<TClass>();
}
GetAndActivateAllAssignableTo定义为:
public static class ReflectorHelper
{
/// <summary>
/// Fetches and prepares for initialization without any constructor parameters all types in the current application domain which are assignable to T.
/// </summary>
/// <typeparam name="T">The type to which all desired types should be assignable to.</typeparam>
/// <returns>IEnumerable of initialized objects.</returns>
public static IEnumerable<T> GetAndActivateAllAssignableTo<T>()
{
return GetAndActivateAllAssignableTo<T>(null);
}
/// <summary>
/// Fetches and prepares for initialization with a given constructor parameters all types in the current application domain which are assignable to T.
/// </summary>
/// <typeparam name="T">The type to which all desired types should be assignable to.</typeparam>
/// <param name="consParams">The constructore parametes array - could be null</param>
/// <returns>IEnumerable of initialized objects.</returns>
public static IEnumerable<T> GetAndActivateAllAssignableTo<T>(object[] consParams)
{
//Deal with null reference for better code consistency
if (consParams == null)
consParams = new object[0];
return from type in AppDomain.CurrentDomain.GetAllAssignableTo<T>()
where type.IsInstantiable()
select (T)Activator.CreateInstance(type, consParams);
}
/// <summary>
/// Gets the flag which shows whether an object of a given type could be possibly(not guaranteed) instantiated.
/// </summary>
/// <param name="type">The type to check.</param>
/// <returns>The flag which shows whether an object of a given type could be possibly(not guaranteed) instantiated.</returns>
public static Boolean IsInstantiable(this Type type)
{
if (type == null)
throw new ArgumentNullException("type", "The type is null");
if (type.IsAbstract)
return false;
if (type.IsGenericTypeDefinition)
return false;
if (type.IsInterface)
return false;
return true;
}
/// <summary>
/// Gets all types which are assignable to T type variables.
/// </summary>
/// <typeparam name="T">The type to which desired types should be assignable.</typeparam>
/// <param name="appDomain">The app domain which assemblies should be checked</param>
/// <returns>The IEnumerable of all types which are assignable to T type variables.</returns>
public static IEnumerable<Type> GetAllAssignableTo<T>(this AppDomain appDomain)
{
if (appDomain == null)
throw new ArgumentNullException("appDomain", "The app domain is null");
return GetAllAssignableTo(appDomain, typeof(T));
}
/// <summary>
/// Gets all types which are assignable to T type variables.
/// </summary>
/// <param name="appDomain">The app domain which assemblies should be checked</param>
/// <param name="assignToType">The type to which desired types should be assignable.</param>
/// <returns>The IEnumerable of all types which are assignable to T type variables.</returns>
public static IEnumerable<Type> GetAllAssignableTo(this AppDomain appDomain, Type assignToType)
{
if (appDomain == null)
throw new ArgumentNullException("appDomain", "The app domain is null");
if (assignToType == null)
throw new ArgumentNullException("assignToType", "The type to check is null");
return from asm in appDomain.GetAssemblies()
from type in asm.GetExportedTypes()
where assignToType.IsAssignableFrom(type)
select type;
}
}
编辑:@Tracey23是的,它不完全是你想要的。它实例化了所有可赋值给TClass
的类(!!在这段代码中,TClass甚至可以是一个接口!!),任何TClass
当然都可以赋值给TClass
。
对于这个解决方案,您可以使您的基类abstract
,因为除了作为组件的基类之外,您可以将其用于任何其他功能,或者将GetAllAssignableTo
更改为在条件下使用(!assignToType.Equals(type))
:
public static IEnumerable<Type> GetAllAssignableTo(this AppDomain appDomain, Type assignToType)
{
if (appDomain == null)
throw new ArgumentNullException("appDomain", "The app domain is null");
if (assignToType == null)
throw new ArgumentNullException("assignToType", "The type to check is null");
return from asm in appDomain.GetAssemblies()
from type in asm.GetExportedTypes()
where assignToType.IsAssignableFrom(type) && (!assignToType.Equals(type)) // !!!!!!
select type;
}
但是它会改变语义,所以您可能想要重命名这些方法,以反映它们将不再在结果中包含Base类型
从固定返回类型开始。
SubClasses<TClass>()
返回IEnumerable<Type>
,因为它返回一个类型对象序列。PopulateListWithObjects<TClass>()
将返回一个包含给定类型实例的列表,所以List<>
的类型参数应该是最派生的基类——我想这将是TClass
。换句话说,我认为你的意思是
private static IEnumerable<TClass> PopulateListWithObjects<TClass>()
{
var listWithObjects = new List<TClass>();
// todo: add objects here
return listWithObjects;
}
现在,您将如何实际创建实例并将其放入列表是另一个问题,您还没有给出足够的信息来回答这个问题。