无法将子类对象放入列表中

时间:2014-08-20 07:50:51

标签: c# .net reflection activator

你能帮我编写一个创建对象列表的方法吗?

  1. 我有一个包含3个子类的类。
  2. 我创建了一个将所有子类放入列表的方法。
  3. 现在我在创建包含对象的列表时遇到问题 - 步骤2中每个子类一个。
  4. 请注意,列表应该具有父类的类型,因为它将引用子类'多态的对象。
  5. 澄清: 我想有一个类似于

    的列表
    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 {}
    }
    

2 个答案:

答案 0 :(得分:1)

如果您想获得所需的结果,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,因为您怀疑是否将其用于组件的基类以外的任何其他容量或更改{{1}在条件中使用GetAllAssignableTo

(!assignToType.Equals(type))

但它会改变语义,因此您可能希望重命名此方法以反映它们将不再包含结果中的Base类型。

答案 1 :(得分:0)

首先修复返回类型。

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; 
}

现在你要如何实际创建列入列表的实例是另一个问题,而你还没有提供足够的信息来回答它。