.NET,C#,反思:列出一个领域,本身具有字段的字段(.NET, C#, Reflection:

2019-06-25 19:04发布

在.NET&C#,假设ClassB具有字段的类型是ClassA 。 人们可以很容易地使用方法GetFields列出ClassB的领域。 不过,我想列出这些领域的ClassB本身具有字段的字段。 例如, ClassB的字段x具有字段bsi 。 我想(编程)列出这些领域(由我在下面的代码注释的建议)。

class ClassA
    {
    public  byte    b ;
    public  short   s ;
    public  int i ;
    }

class ClassB
    {
    public  long    l ;
    public  ClassA  x ;
    }

class MainClass
    {
    public static void Main ( )
        {
        ClassA myAObject = new ClassA () ;
        ClassB myBObject = new ClassB () ;

        //  My goal is this:
        //    ***Using myBObject only***, print its fields, and the fields
        //    of those fields that, *themselves*, have fields.
        //  The output should look like this:
        //    Int64   l
        //    ClassA  x
        //               Byte   b
        //               Int16  s
        //               Int32  i

        }
    }

Answer 1:

使用FieldInfo.FieldType反映过来在你的类中的字段的类型。 例如

fieldInfo.FieldType.GetFields();

下面是一个使用递归在你的情况下根据你的代码的完整示例ClassZClassA 。 如果你有一个循环对象图它打破。

using System;
using System.Reflection;

class ClassA {
  public byte b;
  public short s; 
  public int i;
}

class ClassB {
  public long l;
  public ClassA x;
}

class MainClass {

  public static void Main() {
    ClassB myBObject = new ClassB();
    WriteFields(myBObject.GetType(), 0);
  }

  static void WriteFields(Type type, Int32 indent) {
    foreach (FieldInfo fieldInfo in type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) {
      Console.WriteLine("{0}{1}\t{2}", new String('\t', indent), fieldInfo.FieldType.Name, fieldInfo.Name);
      if (fieldInfo.FieldType.IsClass)
        WriteFields(fieldInfo.FieldType, indent + 1);
    }
  }

}


Answer 2:

这确实类这已经存在! 看看微软C#示例为Visual Studio: http://code.msdn.microsoft.com/Release/ProjectReleases.aspx?ProjectName=csharpsamples&ReleaseId=8

具体来说,看ObjectDumper样品,因为它去正层次深。 例如:

ClassB myBObject = new ClassB();
...
ObjectDumper.Write(myBObject, Int32.MaxValue); 
//Default 3rd argument value is Console.Out, but you can use 
//any TextWriter as the optional third argument

它已经考虑到无论是在图形对象已被访问,值类型与对象类型与枚举类型,等等。



Answer 3:

请尝试以下操作。 它可以让你控制你有多深下降到类型层次,只能沦落成非基本类型。

public static class FieldExtensions
{
  public static IEnumerable<FieldInfo> GetFields( this Type type, int depth )
  {
    if( depth == 0 )
      return Enumerable.Empty<FieldInfo>();

    FieldInfo[] fields = type.GetFields();
    return fields.Union(fields.Where( fi => !fi.IsPrimitive )
                              .SelectMany( f => f.FieldType.GetFields( depth -1 ) );
  }
}


Answer 4:

你需要编写需要的对象的递归方法,遍历其字段( obj.GetType().GetFields()并打印原始类型的字段的值,并自称为一个类(而不是String ) 。

你需要为递归使用缩进大小的参数。

编辑 :您还需要一些机制来防止用于循环对象图堆栈溢出。 我建议将限制在缩进参数。



Answer 5:

这里有一个天真的实现:

    private static void ListFields(Type type)
    {
        Console.WriteLine(type.Name);
        foreach (var field in type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance))
        {
            Console.WriteLine(string.Format("{0} of type {1}", field.Name, field.FieldType.Name));
            if (field.FieldType.IsClass)
            {
                ListFields(field.FieldType);
            }

        }
    }

需要注意以下几点:

  • 防止堆栈溢出。 也就是说,如果A - > B和B-> A,那么这将炸毁。 您可以通过只解决到一定程度解决此
  • 字符串是引用类型,但很多人希望它更像是一个值类型。 所以,你可能不想打电话ListFields如果类型为字符串。


文章来源: .NET, C#, Reflection: list the fields of a field that, itself, has fields