Where are my fields?

Recently Karl added the ability to view the non-public fields of objects in our Mole visualizer, a feature he termed BlackOps. However when reviewing it, I noticed that some fields that I know exist were not being displayed. What we were doing – targetType.GetFields(BindingFlags.NonPublic Or BindingFlags.Instance Or BindingFlags.DeclaredOnly) – seemed to be right but it didn’t return the results expected.

So lets take a look at an example.

    public class A

    {

        private string _private;

        internal string _internal;

        protected string _protected;

        internal protected string _internalProtected;

    }

 

    public class B : A

    {

 

    }

If we check the results of GetFields for these two types:

int aFieldCount = typeof(A).GetFields(BindingFlags.Instance | BindingFlags.NonPublic).Length;

int bFieldCount = typeof(B).GetFields(BindingFlags.Instance | BindingFlags.NonPublic).Length;

When you execute this code, you will find that aFieldCount is 4 but bFieldCount is 3. This is obviously not what we want for Mole since we’re looking to display all the field values (including those not visible to the type itself). The problem is that GetFields will only return Private fields if they are defined by that type – it will not return the private fields of any base classes. The solution is pretty simple – only get the fields defined by each type and walk up the BaseType chain. To get only the fields defined on the type, we add in the BindingFlags.DeclaredOnly flag and then we just use a loop to walk up the base types.

    Type type = typeof(B);

    int fieldCount = 0;

 

    while (null != type)

    {

        fieldCount += type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.DeclaredOnly).Length;

        type = type.BaseType;

    }

About these ads

7 Responses to “Where are my fields?”

  1. Josh Smith Says:

    Great post! I imagine that the BinaryFormatter must do this same trick as well.

    Keep the posts coming!

  2. Omer van Kloeten Says:

    Why would you even use DeclaredOnly?
    Using BindingFlags.Instance | BindingFlags.NonPublic will get you the same result and even more quickly as you don’t have to do a reflection query on every node in the hierarchy tree…

  3. agsmith Says:

    The whole point of the article is that calling GetFields on a type will NOT give you the same results as calling GetFields for each base type. Calling GetFields on the most derived type will not return any of the private fields defined by its base classes. That is why in my example, using GetFields with Instance | NonPublic for Type B does not include the “_private” field.

    Therefore, we have to iterate the basetype of the initial type. The reason you use DeclaredOnly is so that you do not get duplicate fields back. When using Instance | NonPublic, even though you will not get the private fields declared by the base classes, you will get the protected, internal and internal protected fields declared by the base class.

    So if you class A has 10 internal fields and class B derives from class A, if you called GetFields for type B – you would get the 10 internal fields defined on class A. Then when you moved to the base class – A – and called GetFields on it, you would again get the same 10 internal fields. Basically I only want to process each field once. Otherwise you have to track if you processed the field already.

  4. agsmith Says:

    Hi Josh. You’re absolutely right. I didn’t actually think about it but checking it out in reflector, the FormatterServices’s InternalGetSerializableMembers does except it seems that they are not using DeclaredOnly so they’re actually returning the same fields multiple times.

    Actually if you test it out, you’ll see that they basically do:

    [Serializable]
    public class A
    {
    private int _p;
    internal int _i;
    }

    [Serializable]
    public class B : A
    {

    }

    [Serializable]
    public class C : B
    {

    }

    Then get the serializable members and check their value:

    MemberInfo[] members = FormatterServices.GetSerializableMembers(typeof(C));

    C c = new C();
    c._i = 10;

    foreach (MemberInfo member in members)
    {
    FieldInfo field = member as FieldInfo;
    Debug.Assert(null != field);

    string val = string.Format(“{0} = {1}”,
    field.Name, field.GetValue(c));

    Debug.WriteLine(val);
    }

    This results in:
    _i = 10
    B+_i = 10
    A+_p = 0
    A+_i = 10

    So while some of the “_i” values look different (because they’re using SerializationFieldInfo which is returning the base type name), they’re all referencing the same underlying field.

  5. Karl Shifflett Says:

    Andrew,

    Thank you so very much for the hard work in putting out, Mole For Visual Studio.

    Best to you,

    Karl

  6. Idetrorce Says:

    very interesting, but I don’t agree with you
    Idetrorce

  7. agsmith Says:

    Idetrorce,
    Can you explain what it is that you don’t agree with?
    -Andrew

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s


Follow

Get every new post delivered to your Inbox.

%d bloggers like this: