Get all fields from static classes inside static class with reflection
Asked Answered
H

3

16

I have a static class that contains a lot of static classes. Each inner static class contains fields. I want to get all fields of all inner static classes.

public static class MyClass
{
    public static class MyInnerClass1
    {
        public const string Field1 = "abc";
        public const string Field2 = "def";
        public const string Field3 = "ghi";
    }
    public static class MyInnerClass2
    {
        public const int Field1 = 1;
        public const int Field2 = 2;
        public const int Field3 = 3;
    }
    ...
}

I would like to print out the name of each inner class followed by the name and value of each field.

For example:

MyInnerClass

Field1 = "abc"

...

I have no problem with getting the name of all the classes:

var members = typeof(MyClass).GetMembers(BindingFlags.Public | BindingFlags.Static);

var str = ""; 
foreach (var member in members)
{
    str += member.Name +" ";             
}

Or the name and value of all fields in a specific class:

var fields = typeof(MyClass.MyInnerClass1).GetFields();
foreach (var field in fields)
{
    str += field.Name + "-";
    str += field.GetValue(typeof(MyClass.MyInnerClass1));
}

But how do I combine this? The names and the number of inner static classes may change.

Hillier answered 12/3, 2013 at 16:25 Comment(0)
M
18

Try the following

var builder = new StringBuilder();
foreach (var type in typeof(MyClass).GetNestedTypes(BindingFlags.Public | BindingFlags.NonPublic))
{
  if (!type.IsAbstract)
  {
     continue;
  }

  builder.AppendLine(type.Name);
  foreach (var field in type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static)) {
     var msg = String.Format("{0} = {1}", field.Name, field.GetValue(null));
     builder.AppendLine(msg);
  }
}

string output = builder.ToString();

The use of !type.IsAbstract is done to weed on non-static nested types. A static type in C# is generated as abstract under the hood.

Also my solution will pick up both public and non-public members (both types and fields). I'm not sure if this was your intent or not so you may want to modify that part of my solution.

Midsummer answered 12/3, 2013 at 16:32 Comment(0)
U
12

You need to recursively loop through type.GetNestedTypes():

IEnumerable<FieldInfo> GetAllFields(Type type) {
    return type.GetNestedTypes().SelectMany(GetAllFields)
               .Concat(type.GetFields());
}
Uvarovite answered 12/3, 2013 at 16:27 Comment(0)
L
0

If it's supposed that each class might have some fields and some nested classes within it, and nesting level might be more than just 2 levels:

public static IEnumerable<string> GetConstants(Type type)
{
    foreach (var member in type.GetMembers(BindingFlags.Public | BindingFlags.Static))
    {
        if (member.MemberType == MemberTypes.Field)
            yield return type.GetField(member.Name).GetValue(null) as string;
        else if (member.MemberType == MemberTypes.NestedType)
        {
            foreach (var nestedField in GetConstants(type.GetNestedType(member.Name)))
                yield return nestedField;
        }
    }
}

And for many reasons we may need to append hierarchy to result values. Let's say each class CAN have a field called 'Prefix':

public static IEnumerable<string> GetConstants(Type type)
{
    var prefix = type.GetField("Prefix")?.GetValue(null) ?? type.Name;

    foreach (var member in type.GetMembers(BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy))
    {
        if (member.Name == "Prefix")
            continue;

        if (member.MemberType == MemberTypes.Field)
            yield return $"{prefix}.{type.GetField(member.Name).GetValue(null) as string}";
        else if (member.MemberType == MemberTypes.NestedType)
        {
            foreach (var nestedField in GetConstants(type.GetNestedType(member.Name)))
                yield return $"{prefix}.{nestedField}";
        }
    }
}
Lexington answered 28/12, 2023 at 6:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.