Sometimes you need to access the private fields and methods from code outside of the class – for testing, experimentation, and to hack around issues.

.NET has long provided a solution to this problem: reflection. But, reflection code is verbose and messy to write. Exposed object uses dynamic typing in C# 4 to let you access internals of a class with simple and conscise code.

Simple Example
As a simple example, I’ll show how to access internals of the standard List<T> class from the BCL standard library. Let’s create an instance of the List<int> type:

List<int> realList = new List<int>();

To access the internals of List<int>, you’ll create an ExposedObject over the object:

dynamic exposedList = Exposed.From(realList);

And now, via the exposedList object, you can access both private and public members of the List<> class:

// Read a private field - prints 0
Console.WriteLine(exposedList._size);

// Modify a private field
exposedList._items = new int[] { 5, 4, 3, 2, 1 };

// Modify another private field
exposedList._size = 5;

// Call a private method
exposedList.EnsureCapacity(20);

You can still use the public APIs on the exposed list:

// Add a value to the list
exposedList.Add(0);

// Enumerate the list. Prints "5 4 3 2 1 0"
foreach (var x in exposedList) Console.WriteLine(x);


What else can you do with ExposedObject?
You can call static methods by creating an ExposedClass over the class. For example, let’s call the private File.InternalExists() static method that skips error checking before making the real system call:

dynamic fileType = ExposedClass.From(typeof(System.IO.File));
bool exists = fileType.InternalExists("somefile.txt");You can call generic methods (static or non-static) too:

dynamic enumerableType = ExposedClass.From(typeof(System.Linq.Enumerable));
Console.WriteLine(
    enumerableType.Max<int>(new[] { 1, 3, 5, 3, 1 }));

Type inference for generics works too. You don’t have to specify the int generic argument in the Max method call:

dynamic enumerableType = ExposedClass.From(typeof(System.Linq.Enumerable));
Console.WriteLine(
    enumerableType.Max(new[] { 1, 3, 5, 3, 1 }));

Just to clarify… I had to write special code to handle all of these different cases. Deciding which method should be called is normally done at compile time. The logic on overload resolution is hidden away in the compiler, and so unavailable at runtime. To duplicate the method binding rules, we have to duplicate the logic of the compiler.

You can also cast a dynamic object either to its own type, or to a base class:

List<int> realList = new List<int>();
dynamic exposedList = ExposedObject.From(realList);

List<int> realList2 = exposedList;
Console.WriteLine(realList == realList2); // Prints "true"

So, after casting the exposed object (or assigning it into an appropriately typed variable), you can get back the original object!

Last edited Apr 28, 2010 at 2:22 AM by igoro, version 4

Comments

jonathanmv Jan 3, 2012 at 3:24 PM 
The simple example is wrong.
dynamic exposedList = Exposed.From(realList);
should be
dynamic exposedList = ExposedObject.From(realList);