A ToDynamic() Extension Method For Fluent Reflection

Recently I needed to demonstrate some code with reflection, but I felt it inconvenient and tedious. To simplify the reflection coding, I created a ToDynamic() extension method. The source code can be downloaded from here.

Problem

One example for complex reflection is in LINQ to SQL. The DataContext class has a property Privider, and this Provider has an Execute() method, which executes the query expression and returns the result. Assume this Execute() needs to be invoked to query SQL Server database, then the following code will be expected:

using (NorthwindDataContext database = new NorthwindDataContext())
{
    // Constructs the query.
    IQueryable<Product> query = database.Products.Where(product => product.ProductID > 0)
                                                 .OrderBy(product => product.ProductName)
                                                 .Take(2);
<span style="color: green;">// Executes the query. Here reflection is required,
// because Provider, Execute(), and ReturnValue are not public members. The following code cannot compile.
</span><span style="color: #2b91af;">IEnumerable</span>&lt;<span style="color: #2b91af;">Product</span>&gt; results = database.<span style="text-decoration: underline;">Provider</span>.<span style="text-decoration: underline;">Execute</span>(query.Expression).<span style="text-decoration: underline;">ReturnValue</span>;

<span style="color: green;">// Processes the results. </span>
<span style="color: blue;">foreach </span>(<span style="color: #2b91af;">Product </span>product <span style="color: blue;">in </span>results)
{
    <span style="color: #2b91af;">Console</span>.WriteLine(<span style="color: #a31515;">"{0}, {1}"</span>, product.ProductID, product.ProductName);
}

}

Of course, this code cannot compile. And, no one wants to write code like this. Again, this is just an example of complex reflection.

using (NorthwindDataContext database = new NorthwindDataContext())
{
    // Constructs the query.
    IQueryable<Product> query = database.Products.Where(product => product.ProductID > 0)
                                                 .OrderBy(product => product.ProductName)
                                                 .Take(2);
<span style="color: green;">// database.Provider
</span><span style="color: #2b91af;">PropertyInfo </span>providerProperty = database.GetType().GetProperty(
    <span style="color: #a31515;">"Provider"</span>, <span style="color: #2b91af;">BindingFlags</span>.NonPublic | <span style="color: #2b91af;">BindingFlags</span>.GetProperty | <span style="color: #2b91af;">BindingFlags</span>.Instance);
<span style="color: blue;">object </span>provider = providerProperty.GetValue(database, <span style="color: blue;">null</span>);

<span style="color: green;">// database.Provider.Execute(query.Expression)
// Here GetMethod() cannot be directly used,
// because Execute() is a explicitly implemented interface method.
</span><span style="color: #2b91af;">Assembly </span>assembly = <span style="color: #2b91af;">Assembly</span>.Load(<span style="color: #a31515;">"System.Data.Linq"</span>);
<span style="color: #2b91af;">Type </span>providerType = assembly.GetTypes().SingleOrDefault(
    type =&gt; type.FullName == <span style="color: #a31515;">"System.Data.Linq.Provider.IProvider"</span>);
<span style="color: #2b91af;">InterfaceMapping </span>mapping = provider.GetType().GetInterfaceMap(providerType);
<span style="color: #2b91af;">MethodInfo </span>executeMethod = mapping.InterfaceMethods.Single(method =&gt; method.Name == <span style="color: #a31515;">"Execute"</span>);
<span style="color: #2b91af;">IExecuteResult </span>executeResult = 
    executeMethod.Invoke(provider, <span style="color: blue;">new object</span>[] { query.Expression }) <span style="color: blue;">as </span><span style="color: #2b91af;">IExecuteResult</span>;

<span style="color: green;">// database.Provider.Execute(query.Expression).ReturnValue
</span><span style="color: #2b91af;">IEnumerable</span>&lt;<span style="color: #2b91af;">Product</span>&gt; results = executeResult.ReturnValue <span style="color: blue;">as </span><span style="color: #2b91af;">IEnumerable</span>&lt;<span style="color: #2b91af;">Product</span>&gt;;

<span style="color: green;">// Processes the results.
</span><span style="color: blue;">foreach </span>(<span style="color: #2b91af;">Product </span>product <span style="color: blue;">in </span>results)
{
    <span style="color: #2b91af;">Console</span>.WriteLine(<span style="color: #a31515;">"{0}, {1}"</span>, product.ProductID, product.ProductName);
}

}

This may be not straight forward enough. So here is a solution implementing fluent reflection with a ToDynamic() extension method:

IEnumerable<Product> results = database.ToDynamic() // Starts fluent reflection. 
                                       .Provider.Execute(query.Expression).ReturnValue;

C# 4.0 dynamic

In this kind of scenarios, it is easy to have dynamic in mind, which enables developer to write whatever code after a dot:

using (NorthwindDataContext database = new NorthwindDataContext())
{
    // Constructs the query.
    IQueryable<Product> query = database.Products.Where(product => product.ProductID > 0)
                                                 .OrderBy(product => product.ProductName)
                                                 .Take(2);
<span style="color: green;">// database.Provider
</span><span style="color: blue;">dynamic </span>dynamicDatabase = database;
<span style="color: blue;">dynamic </span>results = dynamicDatabase.Provider.Execute(query).ReturnValue;

}

This throws a RuntimeBinderException at runtime:

'System.Data.Linq.DataContext.Provider' is inaccessible due to its protection level.

Here dynamic is able find the specified member. So the next thing is just writing some custom code to access the found member.

.NET 4.0 DynamicObject, and DynamicWrapper<T>

Where to put the custom code for dynamic? The answer is DynamicObject’s derived class. I first heard of DynamicObject from Anders Hejlsberg's video in PDC2008. It is very powerful, providing useful virtual methods to be overridden, like:

  • TryGetMember()
  • TrySetMember()
  • TryInvokeMember()

etc.  (In 2008 they are called GetMember, SetMember, etc., with different signature.)

For example, if dynamicDatabase is a DynamicObject, then the following code:

dynamicDatabase.Provider

will invoke dynamicDatabase.TryGetMember() to do the actual work, where custom code can be put into.

Now create a type to inherit DynamicObject:

public class DynamicWrapper<T> : DynamicObject
{
    private readonly bool _isValueType;
<span style="color: blue;">private readonly </span><span style="color: #2b91af;">Type </span>_type;

<span style="color: blue;">private </span>T _value; <span style="color: green;">// Not readonly, for value type scenarios.
public DynamicWrapper(ref T value) // Uses ref in case of value type. { if (value == null) { throw new ArgumentNullException("value"); }
    <span style="color: blue;">this</span>._value = value;
    <span style="color: blue;">this</span>._type = value.GetType();
    <span style="color: blue;">this</span>._isValueType = <span style="color: blue;">this</span>._type.IsValueType;
}

<span style="color: blue;">public override bool </span>TryGetMember(<span style="color: #2b91af;">GetMemberBinder </span>binder, <span style="color: blue;">out object </span>result)
{
    <span style="color: green;">// Searches in current type's public and non-public properties.
    </span><span style="color: #2b91af;">PropertyInfo </span>property = <span style="color: blue;">this</span>._type.<span style="text-decoration: underline;">GetTypeProperty</span>(binder.Name);
    <span style="color: blue;">if </span>(property != <span style="color: blue;">null</span>)
    {
        result = property.GetValue(<span style="color: blue;">this</span>._value, <span style="color: blue;">null</span>).<span style="text-decoration: underline;">ToDynamic</span>();
        <span style="color: blue;">return true</span>;
    }

    <span style="color: green;">// Searches in explicitly implemented properties for interface.
    </span><span style="color: #2b91af;">MethodInfo </span>method = <span style="color: blue;">this</span>._type.<span style="text-decoration: underline;">GetInterfaceMethod</span>(<span style="color: blue;">string</span>.Concat(<span style="color: #a31515;">"get_"</span>, binder.Name), <span style="color: blue;">null</span>);
    <span style="color: blue;">if </span>(method != <span style="color: blue;">null</span>)
    {
        result = method.Invoke(<span style="color: blue;">this</span>._value, <span style="color: blue;">null</span>).<span style="text-decoration: underline;">ToDynamic</span>();
        <span style="color: blue;">return true</span>;
    }

    <span style="color: green;">// Searches in current type's public and non-public fields.
    </span><span style="color: #2b91af;">FieldInfo </span>field = <span style="color: blue;">this</span>._type.<span style="text-decoration: underline;">GetTypeField</span>(binder.Name);
    <span style="color: blue;">if </span>(field != <span style="color: blue;">null</span>)
    {
        result = field.GetValue(<span style="color: blue;">this</span>._value).<span style="text-decoration: underline;">ToDynamic</span>();
        <span style="color: blue;">return true</span>;
    }

    <span style="color: green;">// Searches in base type's public and non-public properties.
    </span>property = <span style="color: blue;">this</span>._type.<span style="text-decoration: underline;">GetBaseProperty</span>(binder.Name);
    <span style="color: blue;">if </span>(property != <span style="color: blue;">null</span>)
    {
        result = property.GetValue(<span style="color: blue;">this</span>._value, <span style="color: blue;">null</span>).<span style="text-decoration: underline;">ToDynamic</span>();
        <span style="color: blue;">return true</span>;
    }

    <span style="color: green;">// Searches in base type's public and non-public fields.
    </span>field = <span style="color: blue;">this</span>._type.<span style="text-decoration: underline;">GetBaseField</span>(binder.Name);
    <span style="color: blue;">if </span>(field != <span style="color: blue;">null</span>)
    {
        result = field.GetValue(<span style="color: blue;">this</span>._value).<span style="text-decoration: underline;">ToDynamic</span>();
        <span style="color: blue;">return true</span>;
    }

    <span style="color: green;">// The specified member is not found.
    </span>result = <span style="color: blue;">null</span>;
    <span style="color: blue;">return false</span>;
}

<span style="color: green;">// Other overridden methods are not listed.</span>

}

In the above code, GetTypeProperty(), GetInterfaceMethod(), GetTypeField(), GetBaseProperty(), and GetBaseField() are extension methods for Type class. For example:

internal static class TypeExtensions
{
    internal static FieldInfo GetBaseField(this Type type, string name)
    {
        Type @base = type.BaseType;
        if (@base == null)
        {
            return null;
        }
    <span style="color: blue;">return </span>@base.GetTypeField(name) ?? @base.GetBaseField(name);
}

<span style="color: blue;">internal static </span><span style="color: #2b91af;">PropertyInfo </span>GetBaseProperty(<span style="color: blue;">this </span><span style="color: #2b91af;">Type </span>type, <span style="color: blue;">string </span>name)
{
    <span style="color: #2b91af;">Type </span>@base = type.BaseType;
    <span style="color: blue;">if </span>(@base == <span style="color: blue;">null</span>)
    {
        <span style="color: blue;">return null</span>;
    }

    <span style="color: blue;">return </span>@base.GetTypeProperty(name) ?? @base.GetBaseProperty(name);
}

<span style="color: blue;">internal static </span><span style="color: #2b91af;">MethodInfo </span>GetInterfaceMethod(<span style="color: blue;">this </span><span style="color: #2b91af;">Type </span>type, <span style="color: blue;">string </span>name, <span style="color: blue;">params object</span>[] args)
{
    <span style="color: blue;">return
        </span>type.GetInterfaces().Select(type.GetInterfaceMap).SelectMany(mapping =&gt; mapping.TargetMethods)
            .FirstOrDefault(
                method =&gt;
                method.Name.Split(<span style="color: #a31515;">'.'</span>).Last().Equals(name, <span style="color: #2b91af;">StringComparison</span>.Ordinal) &amp;&amp;
                method.GetParameters().Count() == args.Length &amp;&amp;
                method.GetParameters().Select(
                    (parameter, index) =&gt;
                    parameter.ParameterType.IsAssignableFrom(args[index].GetType())).Aggregate(
                        <span style="color: blue;">true</span>, (a, b) =&gt; a &amp;&amp; b));
}

<span style="color: blue;">internal static </span><span style="color: #2b91af;">FieldInfo </span>GetTypeField(<span style="color: blue;">this </span><span style="color: #2b91af;">Type </span>type, <span style="color: blue;">string </span>name)
{
    <span style="color: blue;">return
        </span>type.GetFields(
            <span style="color: #2b91af;">BindingFlags</span>.GetField | <span style="color: #2b91af;">BindingFlags</span>.Instance | <span style="color: #2b91af;">BindingFlags</span>.Static | <span style="color: #2b91af;">BindingFlags</span>.Public |
            <span style="color: #2b91af;">BindingFlags</span>.NonPublic).FirstOrDefault(
                field =&gt; field.Name.Equals(name, <span style="color: #2b91af;">StringComparison</span>.Ordinal));
}

<span style="color: blue;">internal static </span><span style="color: #2b91af;">PropertyInfo </span>GetTypeProperty(<span style="color: blue;">this </span><span style="color: #2b91af;">Type </span>type, <span style="color: blue;">string </span>name)
{
    <span style="color: blue;">return
        </span>type.GetProperties(
            <span style="color: #2b91af;">BindingFlags</span>.GetProperty | <span style="color: #2b91af;">BindingFlags</span>.Instance | <span style="color: #2b91af;">BindingFlags</span>.Static |
            <span style="color: #2b91af;">BindingFlags</span>.Public | <span style="color: #2b91af;">BindingFlags</span>.NonPublic).FirstOrDefault(
                property =&gt; property.Name.Equals(name, <span style="color: #2b91af;">StringComparison</span>.Ordinal));
}

<span style="color: green;">// Other extension methods are not listed.

}

So now, when invoked, TryGetMember() searches the specified member and invoke it. The code can be written like this:

dynamic dynamicDatabase = new DynamicWrapper<NorthwindDataContext>(ref database);
dynamic dynamicReturnValue = dynamicDatabase.Provider.Execute(query.Expression).ReturnValue;

This greatly simplified reflection.

ToDynamic() and fluent reflection

To make it even more straight forward, A ToDynamic() method is provided:

public static class DynamicWrapperExtensions
{
    public static dynamic ToDynamic<T>(this T value)
    {
        return new DynamicWrapper<T>(ref value);
    }
}

and a ToStatic() method is provided to unwrap the value:

public class DynamicWrapper<T> : DynamicObject
{
    public T ToStatic()
    {
        return this._value;
    }
}

In the above TryGetMember() method, please notice it does not output the member’s value, but output a wrapped member value (that is, memberValue.ToDynamic()). This is very important to make the reflection fluent.

Now the code becomes:

IEnumerable<Product> results = database.ToDynamic() // Here starts fluent reflection. 
                                       .Provider.Execute(query.Expression).ReturnValue
                                       .ToStatic(); // Unwraps to get the static value. 

With the help of TryConvert():

public class DynamicWrapper<T> : DynamicObject
{
    public override bool TryConvert(ConvertBinder binder, out object result)
    {
        result = this._value;
        return true;
    }
}

ToStatic() can be omitted:

IEnumerable<Product> results = database.ToDynamic() 
                                       .Provider.Execute(query.Expression).ReturnValue;
                                       // Automatically converts to expected static value.

Take a look at the reflection code at the beginning of this post again. Now it is much much simplified!

Special scenarios

In 90% of the scenarios ToDynamic() is enough. But there are some special scenarios.

Access static members

Using extension method ToDynamic() for accessing static members does not make sense. Instead, DynamicWrapper<T> has a parameterless constructor to handle these scenarios:

public class DynamicWrapper<T> : DynamicObject
{
    public DynamicWrapper() // For static.
    {
        this._type = typeof(T);
        this._isValueType = this._type.IsValueType;
    }
}

The reflection code should be like this:

dynamic wrapper = new DynamicWrapper<StaticClass>();
int value = wrapper._value;
int result = wrapper.PrivateMethod();

So accessing static member is also simple, and fluent of course.

Change instances of value types

Value type is much more complex. The main problem is, value type is copied when passing to a method as a parameter.

This is why ref keyword is used for the constructor. That is, if a value type instance is passed to DynamicWrapper<T>, the instance itself will be stored in this._value of DynamicWrapper<T>. Without the ref keyword, when this._value is changed, the value type instance itself does not change.

Consider FieldInfo.SetValue(). In the value type scenarios, invoking FieldInfo.SetValue(this._value, value) does not change this._value, because it changes the copy of this._value.

I searched the Web and found a solution for setting the value of field:

internal static class FieldInfoExtensions
{
    internal static void SetValue<T>(this FieldInfo field, ref T obj, object value)
    {
        if (typeof(T).IsValueType)
        {
            field.SetValueDirect(__makeref(obj), value); // For value type. 
        }
        else
        {
            field.SetValue(obj, value); // For reference type.
        }
    }
}

Here __makeref is a undocumented keyword of C#.

But method invocation has problem. This is the source code of TryInvokeMember():

public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{
    if (binder == null)
    {
        throw new ArgumentNullException("binder");
    }
<span style="color: #2b91af;">MethodInfo </span>method = <span style="color: blue;">this</span>._type.GetTypeMethod(binder.Name, args) ??
                    <span style="color: blue;">this</span>._type.GetInterfaceMethod(binder.Name, args) ??
                    <span style="color: blue;">this</span>._type.GetBaseMethod(binder.Name, args);
<span style="color: blue;">if </span>(method != <span style="color: blue;">null</span>)
{
    <span style="color: green;">// Oops!
    // If the returnValue is a struct, it is copied to heap.
    </span><span style="color: blue;">object </span>resultValue = method.Invoke(<span style="color: blue;">this</span>._value, args);
    <span style="color: green;">// And result is a wrapper of that copied struct.
    </span>result = <span style="color: blue;">new </span><span style="color: #2b91af;">DynamicWrapper</span>&lt;<span style="color: blue;">object</span>&gt;(<span style="color: blue;">ref </span>resultValue);
    <span style="color: blue;">return true</span>;
}

result = <span style="color: blue;">null</span>;
<span style="color: blue;">return false</span>;

}

If the returned value is of value type, it will definitely copied, because MethodInfo.Invoke() does return object. If changing the value of the result, the copied struct is changed instead of the original struct. And so is the property and index accessing. They are both actually method invocation. For less confusion, setting property and index are not allowed on struct.

Conclusions

The DynamicWrapper<T> provides a simplified solution for reflection programming. It works for normal classes (reference types), accessing both instance and static members.

In most of the scenarios, just remember to invoke ToDynamic() method, and access whatever you want:

StaticType result = someValue.ToDynamic()._field.Method().Property[index];

In some special scenarios which requires changing the value of a struct (value type), this DynamicWrapper<T> does not work perfectly. Only changing struct’s field value is supported.

The source code can be downloaded from here, including a few unit test code.

11 Comments

  • Wrapping the reflection code in a DynamicObject is a clever idea; it certainly makes working with non-public members more pleasant.

    But directly accessing non-public members is risky in general. Private and, to some extent, internal members are implementation details and are not part of the contract exposed by a type. By accessing these members directly, you could be circumventing logic that ensures proper behavior of the object. You're also introducing a dependency on members that are highly subject to change, and that dependency is only checked at runtime.

  • I got a little lost with your LinqToSql example. The query will automatically be executed when it is enumerated, so you can just foreach(var product in query) { ... } or use query.ToList() if you get the results now and enumerate later. Although your dynamicwrapper probably has lots of different usages, I didn't catch why you needed it for LinqToSql.

  • But directly accessing non-public members is risky in general. ->

    Totoally agree. This kind of reflection code should be used ONLY for very special scenarios.

  • I didn't catch why you needed it for LinqToSql ->

    Just like I said at the beginning of the post "no one wants to write code like this. Again, this is just an example of complex reflection" :)

  • Just read your nice article. Our ideas are really similar!!

    My issue is about struct. I think the issue also exists on your AccessPrivateWrapper. When passing a struct to the constructor:
    AccessPrivateWrapper(object o)
    the struct is copied. Then setting field will not change the value of the original struct.

    fld.SetValue(_wrapped,value);
    This also has issue with struct.

    Currently I cannot find a perfect solution. Do you have any idea?

  • Nope. I havn't really thought about that scenario. Will get back after some experimentation.

  • Thanks for sharing!
    Very helpful!

  • Good ideal!

  • @Dixin

    Solution is to use ref

    AccessPrivateWrapper(ref object o)

    Using ref will give a refrence to the value type (which struct is, just like int) So when chaning either the value of the whole type of a field/member of the type will be reflected in the origional object.





  • Hi to every one, the contents existing at this web site are genuinely amazing for people knowledge, well,
    keep up the good work fellows.

  • Hello, i feel that i saw you visited my blog thus i got here to
    go back the favor?.I'm attempting to find issues to improve my site!I
    suppose its adequate to make use of a few of your ideas!!

Add a Comment

As it will appear on the website

Not displayed

Your website