【问题标题】:Reflection , looping throw class hierarchic and finding fields by type反射,循环抛出类层次结构并按类型查找字段
【发布时间】:2012-01-02 11:03:24
【问题描述】:

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

例子

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

谢谢

【问题讨论】:

标签: c# reflection


【解决方案1】:

如果您需要可以在一般情况下工作的东西(任何类层次结构),那么您可以执行以下操作:

您将需要一个递归算法(函数)。该算法将遍历成员,将它们的类型添加到列表中(如果它们尚未添加),然后返回该列表,结合刚刚添加到列表中的类型的成员的类型 - 在这里您进行递归称呼。终止条件是:

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

我没有进行全面的测试,但这至少应该为您指明正确的方向。有趣的问题。我很乐意回答。

【讨论】:

  • 我现在有考试。就在我非常有动力发布代码示例之后! 3-4 小时后见 :)
猜你喜欢
  • 1970-01-01
  • 2013-01-10
  • 2022-10-18
  • 1970-01-01
  • 2011-06-13
  • 2012-10-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多