Question

I need to get all members that represent the exact state of an object using reflection. So these members include fields (FieldInfo) and auto-properties (PropertyInfo). I can get all the FieldInfos using

type.GetFields(); //ok some flags needed here

And get auto implemented properties as mentioned in this link:

public static bool MightBeCouldBeMaybeAutoGeneratedInstanceProperty(this PropertyInfo info)
{
    bool mightBe = info.GetGetMethod().HasCompilerGeneratedAttribute();
    if (!mightBe)
        return false;

    bool maybe = info.DeclaringType.GetFields(BindingFlags.NonPublic | BindingFlags.Instance)
                                   .Where(f => f.Name.Contains(info.Name))
                                   .Where(f => f.Name.Contains("BackingField"))
                                   .Where(f => f.HasCompilerGeneratedAttribute())
                                   .Any();

    return maybe;
}

public static bool HasCompilerGeneratedAttribute(this MemberInfo mi)
{
    return mi.GetCustomAttributes(typeof(CompilerGeneratedAttribute), true).Any();
}

As the answerer says this is indeed brittle. Is there are more standard way of achieving this? I'm thinking, may be something with BindingFlags or so?

type.GetMembers(BindingFlags....) ?
Was it helpful?

Solution

If by "exact state of the object" you simply mean all the instance fields it contains (if not, can you clarify?), then you should be able to do it with a single statement -- there's no significant difference between fields you declare explicitly, and backing fields for auto-properties that the compiler adds for you. If you define a class:

public class FieldInfoTest
{
  private string testField;

  public string TestProperty { get; set; }
}

...you can access them all in one fell swoop with

FieldInfo[] fields = typeof(FieldInfoTest).GetFields(BindingFlags.Instance |
                                                     BindingFlags.Public | 
                                                     BindingFlags.NonPublic);

foreach (var f in fields)
{
  Console.WriteLine(f.Name);
}

This will yield:

testField
<TestProperty>k__BackingField

OTHER TIPS

Jeremy's answer is the best I could get. Here's another alternative (which I originally mentioned in question itself):

public static IEnumerable<MemberInfo> GetStateMembers(this Type t)
{
    return t.GetMembers(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
            .Where(m => m.MemberType == MemberTypes.Field && !((FieldInfo)m).Name.Contains('<')
                     || m.MemberType == MemberTypes.Property && ((PropertyInfo)m).IsAutoProperty());
}

public static bool IsAutoProperty(this PropertyInfo prop)
{
    if (!prop.CanWrite || !prop.CanRead)
        return false;

    return prop.DeclaringType.GetFields(BindingFlags.NonPublic | BindingFlags.Instance)
                             .Any(f => f.Name.Contains("<" + prop.Name + ">"));
}

More explanation on how that works here: https://stackoverflow.com/a/16506710/661933

Little bit hackish, but this gives fields and auto-properties (unlike Jeremy's answer which gives only field infos).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top