I've got a custom attribute BacksCache
that I'm using to mark fields in a class that need to be "defaulted" when certain conditions are met.
I'm using the following code:
Type type = obj.GetType();
FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.FlattenHierarchy);
foreach (FieldInfo field in fields)
{
foreach (Attribute at in field.GetCustomAttributes(true))
if (at is BacksCache)
{
field.SetValue(obj, Utils.DefaultValue(field.FieldType));
}
}
This code works fine, provided that the class inheritance hierarchy is flat. That is to say, if type
is the Type that declares all the attributed fields, everything's great. As soon as I have a class A
from which descends class B
(B : A
) and B
has some attributed fields things fall apart: only the fields declared by A
are detected and "defaulted".
The fields in question are private
or private volatile
, if that makes any difference.
Any ideas on how to fix this?
Beware of the small print for the BindingFlags.FlattenHierarchy option:
Specifies that public and protected static members up the hierarchy should be returned. Private static members in inherited classes are not returned. Static members include fields, methods, events, and properties. Nested types are not returned.
The "static" word in the bolded phrase is an oops, no private members are returned. To work around this you'll need to move up the inheritance chain through Type.BaseType.
Your wording is a bit confusing, which class is the base class A or B? And which one are you reflecting over, the base class or the derived class. I ask because I'm having trouble reproducing your issue. I've tried this and it works fine:
static void Main(string[] args)
{
foreach (var prop in typeof(Sub).GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy))
{
foreach (var attrib in prop.GetCustomAttributes(typeof(DescriptionAttribute), false))
{
Console.WriteLine(prop.Name);
}
}
Console.ReadKey(true);
}
public class Base
{
[Description]
public int IntProp { get; set; }
}
public class Sub : Base
{
[Description]
public string StringProp { get; set; }
}
The output is correct, it shows both properties.
Furthermore, I just noticed you're dealing with Fields. I did this, and still got the correct output:
static void Main(string[] args)
{
foreach (var prop in typeof(Sub).GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy))
{
foreach (var attrib in prop.GetCustomAttributes(typeof(DescriptionAttribute), false))
{
Console.WriteLine(prop.Name);
}
}
Console.ReadKey(true);
}
public class Base
{
[Description]
public int X;
[Description]
public int IntProp { get; set; }
}
public class Sub : Base
{
[Description]
public int Y;
[Description]
public string StringProp { get; set; }
}
Both X and Y get output to the console.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With