Отражение, циклический бросок иерархии классов и поиск полей по типу - PullRequest
0 голосов
/ 02 января 2012

У меня есть большой иерархический класс, который я хотел бы зациклить все его свойства и подчиненные свойства и т.д ..

Пример

public class RootClass
{
   // properties ..
   List<Item> FirstItemsList { get; set;}
   List<Item> SecondItemsList { get; set;}
   SubClass SubClass { get; set;}
}
public class SubClass
{
   // properties ..
   List<Item> ThirdItemsList { get; set;}
}
public class Item
{
   //properties 
}

я хочу функцию, которая будет возвращать мне список всех найденных типов элементов то есть

public IList<Item> GetAllItemsInClass(RootClass entity);

Спасибо

1 Ответ

0 голосов
/ 02 января 2012

Если вам нужно что-то, что будет работать в общем случае (любая иерархия классов), тогда вы можете сделать следующее:

Вам понадобится рекурсивный алгоритм (функция). Алгоритм будет зацикливаться на элементах, добавляя их типы в список (если они еще не добавлены), а затем возвращая этот список, комбинируя с типами членов типа, только что добавленных в список, - здесь вы делаете рекурсивный вызов. Условия прекращения будут:

  1. Тип члена является примитивным (чтобы проверить это использование Type.IsPrimitive).
  2. Отражаемый тип определен в другой сборке. Вы можете проверить определяющую сборку, используя Type.Assembly.

Если вам нужно что-то более простое, используйте вышеописанную технику, но просто используйте оператор if в цикле.

Дайте мне знать, если вы этого хотите или нет, и тогда я опубликую пример кода для вас, когда у меня будет больше времени.

Обновление: Ниже приведен пример кода, показывающий, как вы можете обработать тип и рекурсивно получить все типы, содержащиеся в нем. Вы можете назвать это так: List typesHere = GetTypes(myObject.GetType())

    public static List<Type> GetTypes(Type t)
    {
        List<Type> list = new List<Type>();
        if (t.IsPrimitive)
        {
            if (!list.Contains(t))
                list.Add(t);
            return list;
        }
        else if (!t.Assembly.Equals(System.Reflection.Assembly.GetExecutingAssembly()))
        {
            //if the type is defined in another assembly then we will check its
            //generic parameters. This handles the List<Item> case.
            var genArgs = t.GetGenericArguments();
            if (genArgs != null)
                foreach (Type genericArgumentType in genArgs)
                {
                    if(!list.Contains(genericArgumentType))
                        list.AddRange(GetTypes(genericArgumentType));
                }
            return list;
        }
        else
        {
            //get types of props and gen args
            var types = t.GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).Select(pi => pi.PropertyType).ToList();
            types.AddRange(t.GetGenericArguments());
            foreach (System.Type innerType in types)
            {
                //get the object represented by the property to traverse the types in it.
                if (!list.Contains(innerType))
                    list.Add(innerType);
                else continue; //because the type has been already added and as thus its child types also has been already added.

                var innerInnerTypes = GetTypes(innerType);
                //add the types filtering duplicates
                foreach (Type t1 in innerInnerTypes) //list.AddRange(innerTypes); //without filtering duplicates.
                    if (!list.Contains(t1))
                        list.Add(t1);
            }
            return list;
        }
    }

Поэтому, когда я запустил это для классов, которые вы опубликовали в исходном сообщении (элемент, имеющий два примитивных свойства, как показано ниже), я получил следующий список:

GetTypes(typeof(List<Item>))
Count = 3
    [0]: {Name = "Item" FullName = "AssemblyNameXYZ.Item"}
    [1]: {Name = "String" FullName = "System.String"}
    [2]: {Name = "Int32" FullName = "System.Int32"}

GetTypes(typeof(Item))
Count = 2
    [0]: {Name = "String" FullName = "System.String"}
    [1]: {Name = "Int32" FullName = "System.Int32"}

Reflection.GetTypes(typeof(RootClass))
Count = 5
    [0]: {Name = "List`1" FullName = "System.Collections.Generic.List`1[[AssemblyNameXYZ.Item, AssemblyNameXYZ, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]"}
    [1]: {Name = "Item" FullName = "AssemblyNameXYZ.Item"}
    [2]: {Name = "String" FullName = "System.String"}
    [3]: {Name = "Int32" FullName = "System.Int32"}
    [4]: {Name = "SubClass" FullName = "AssemblyNameXYZ.SubClass"}

Я не проводил всесторонних испытаний, но это должно, по крайней мере, указать вам правильное направление. Веселый вопрос. Мне весело отвечать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...