Raj Raj - 3 months ago 11
C# Question

How to use Reflection to read Static Properties from a Nested Class?

I have some configuration stored in the following data structure which uses nested classes for Organization.

public abstract class LogoSpec
{
public abstract byte[] Logo { get; set; }

public class Web
{
public static float Width { get; set; }
public static float Height { get; set; }

public class A4 : Web
{
public static float Left { get; set; }
public static float Top { get; set; }
}

public class Letter : Web
{
public static float Left { get; set; }
public static float Top { get; set; }
}
}

public class Print
{
public static float Width { get; set; }
public static float Height { get; set; }

public class A4 : Print
{
public static float Left { get; set; }
public static float Top { get; set; }
}

public class Letter : Print
{
public static float Left { get; set; }
public static float Top { get; set; }
}
}
}

public class SampleLogo : LogoSpec
{
public override byte[] Logo { get; set; }
}


I can easily use it when I exactly know what value to use at design time

// Usage
SampleLogo.Web.A4.Height = 10.25f;


How can I write a function that retrieves this value at runtime?

float GetValue(string logoName = "SampleLogo", string layout = "Web", string paperSize = "A4", string property = "Height");

Answer

The way to get that property is actually very straight forward, but you have to provide all necessary BindingFlags:

PropertyInfo p = typeof(SampleLogo.Web.A4).GetProperty("Height", 
    BindingFlags.Static | 
    BindingFlags.FlattenHierarchy | 
    BindingFlags.Public);

FlattenHierarchy is needed to also get properties of base classes.

Now you can use this PropertyInfo to get and set the value:

p.SetValue(null, 14f);
float height = (float)p.GetValue(null);

Update: The complete method could look like this:

public float GetValue(string logoName = "LogoSpec", string layout = "Web", string paperSize = "A4", string property = "Height")
{
    Type logoType = Type.GetType(logoName);
    Type layoutType = logoType?.GetNestedType(layout);
    Type paperType = layoutType?.GetNestedType(paperSize);
    PropertyInfo pi = paperType?.GetProperty("Height", BindingFlags.Static | BindingFlags.FlattenHierarchy | BindingFlags.Public);
    return (float?)pi?.GetValue(null) ?? 0f;
}

But note that instead for "LogoSpec" you would need to use an AssemblyQualifiedName or at least qualify the type name with its namespace.