反射,循环抛出类层次结构,并按类型查找字段

本文关键字:类型 字段 查找 循环 反射 层次结构 | 更新日期: 2023-09-27 18:19:25

我有一个大的层次结构类,我想循环它的所有属性和子属性等。

例子
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. 成员的类型是一个原语(检查这个使用Type.IsPrimitive)。
  2. 被反射的类型在另一个程序集中定义。您可以使用Type.Assembly检查定义程序集。

如果需要更简单的方法,可以使用上面的技巧,但只需在循环中使用If语句。

让我知道这是否是你想要的,然后当我有更多的时间时,我会为你发布一个代码样本。

Update:下面的代码示例展示了如何处理类型并递归地获取其中包含的所有类型。你可以这样调用它: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"}

我没有做全面的测试,但这至少应该为你指出正确的方向。有趣的问题。