Tao Te KaChing
Workin' the cash register of the Great Tao

Dictionaries, Reflection, Private Fields, and Me...

Hello.

So the other day at work I was confronted with a problem.  A particular class we use extensively throughout an enterprise solution was using OO to hide a Dictionary<string, object> from me...BUT ALL FOR NAUGHT!

Said class has a private field which is basically a Dictionary<string, object> instance.  You could add to it just fine via a public method created for that very purpose.  But as is typical with any ongoing large project, we suddenly needed the ability to remove from that field by a given key just for unit testing, and the powers that be frowned heavily on adding a public remove method just for this purpose.  Time for reflection.

Here’s a more generic example of what needed to be done.  Consider the following class:

    public class Test
    {
	public void Add(string s, object o)
	{
		_field.Add(s, o);
	}
        private Dictionary<string, object> _field = new Dictionary<string, object>()
        {
            { "One", 1 },
            { "Two", 2 }
        };
    }

On instantiating Test, we want to get rid of the { "One", 1 } item from _field.  We would normally do this easily with the call:

_field.Remove("One");

But unfortunately, the Dictionary is hidden from us.  We can access it via reflection easily, though:

	Test a = new Test();
	Type TestType = a.GetType();
	FieldInfo ttField = TestType.GetField("_field",
		BindingFlags.NonPublic | BindingFlags.Instance);
	object v = ttField.GetValue(a);

Now that we have our _field ref’d by our object v, we can call it’s Remove function and have our gravy:

	MethodInfo ttFieldDictRemove = v.GetType().GetMethod("Remove");
	ttFieldDictRemove.Invoke(v, new object[] { "One" });

Done.

None of this is necessarily rocket science, but there are two parts to this that can use a little more analysis: the need for the BindingFlags.Instance, and that our GetValue call returns a ref to _field and not a copy.

The BindingFlags.Instance is required to “see” the member field _field.  At first we might simply assume that this is just referring to instance variables versus class variables.  Were _field declared static in Test, we could simply change BindingFlags.Instance to BindingFlags.Static, and we’d be “see”-ing _field again.

However, if _field is not static and public, suddenly we can’t have either BindingFlagsNonPublic is understandable, but why not Instance?  Isn’t _field still an instance variable, just public?  How are accessors involved here?

Really this is just something that can be misleading in the MSDN documentation.  For example, as of today, BindingFlags.Instance is described in the online docs for BindingFlags as:

Instance  -  Specifies that instance members are to be included in the search.

BindingFlags is not so much a search as a filter (as specified on, say, the GetField page).  If we use BindingFlags.Public | BindingFlags.Instance, we’ll then “see” _field.  With no BindingFlags specified, we’ll “see” both instance and class variables that are public.  Interestingly, BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static should return the same as this but doesn’t, even though BindingFlags is a filter.

Now regarding GetValue.  That GetValue returns a ref to _field is obvious when we run our code.  Remove-ing key "One" from object v will result in our instance a of Test no longer having "One" in it’s Dictionary.  Looking at it, however, it just seems it should end up being only a copy, as the code reads something like “Based on what type class Test is, we know there’s a private field named _field, so get it’s value and call that value’s method Remove”.  The underlined “so get it’s value” implies that we’re just getting whatever value that field currently has and not the actual field.  Since _field is a non-primitive (e.g. Dictionary<,>), we can assume that getting _field’s value implies the new Dictionary<,> we’d created in the heap.  With this is mind, GetValue should not work on a primitive type.  We’ll try the following:

    struct S
    {
        public int i;
        public void MinusOne()
        {
            i--;
        }
    }
    class Test
    {
        private S s = new S() { i = 3 };
    }
    class Program
    {
        static void Main(string[] args)
        {
            Test a = new Test();
            Type TestType = a.GetType();
            FieldInfo ttField = TestType.GetField("s", BindingFlags.NonPublic | BindingFlags.Instance);
            object v = ttField.GetValue(a);
            MethodInfo ttFieldStructChange = v.GetType().GetMethod("MinusOne");
            ttFieldStructChange.Invoke(v, new object[] { });
        }
    }

Sure enough, s.i remains 3 after the operation, ergo the need for GetValue’s counterpart SetValue.

I’d love to pour through CLR via C# to make sure I haven’t misled anyone on some internals discoveries here, but in the meantime, if you have anything to add to this piece, please provide your insights in your comments and I’ll update the post.

~zagnut

,,,,,,,,,,,,,,,

COMMENTS