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);

    // Executes the query. Here reflection is required,
    // because Provider, Execute(), and ReturnValue are not public members. The following code cannot compile.
    IEnumerable<Product> results = database.Provider.Execute(query.Expression).ReturnValue;

    // Processes the results. 
    foreach (Product product in results)
    {
        Console.WriteLine("{0}, {1}", 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);

    // database.Provider
    PropertyInfo providerProperty = database.GetType().GetProperty(
        "Provider", BindingFlags.NonPublic | BindingFlags.GetProperty | BindingFlags.Instance);
    object provider = providerProperty.GetValue(database, null);

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

    // database.Provider.Execute(query.Expression).ReturnValue
    IEnumerable<Product> results = executeResult.ReturnValue as IEnumerable<Product>;

    // Processes the results.
    foreach (Product product in results)
    {
        Console.WriteLine("{0}, {1}", 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);

    // database.Provider
    dynamic dynamicDatabase = database;
    dynamic 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;

    private readonly Type _type;

    private T _value; // 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");
        }

        this._value = value;
        this._type = value.GetType();
        this._isValueType = this._type.IsValueType;
    }

    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        // Searches in current type's public and non-public properties.
        PropertyInfo property = this._type.GetTypeProperty(binder.Name);
        if (property != null)
        {
            result = property.GetValue(this._value, null).ToDynamic();
            return true;
        }

        // Searches in explicitly implemented properties for interface.
        MethodInfo method = this._type.GetInterfaceMethod(string.Concat("get_", binder.Name), null);
        if (method != null)
        {
            result = method.Invoke(this._value, null).ToDynamic();
            return true;
        }

        // Searches in current type's public and non-public fields.
        FieldInfo field = this._type.GetTypeField(binder.Name);
        if (field != null)
        {
            result = field.GetValue(this._value).ToDynamic();
            return true;
        }

        // Searches in base type's public and non-public properties.
        property = this._type.GetBaseProperty(binder.Name);
        if (property != null)
        {
            result = property.GetValue(this._value, null).ToDynamic();
            return true;
        }

        // Searches in base type's public and non-public fields.
        field = this._type.GetBaseField(binder.Name);
        if (field != null)
        {
            result = field.GetValue(this._value).ToDynamic();
            return true;
        }

        // The specified member is not found.
        result = null;
        return false;
    }

    // Other overridden methods are not listed.
}

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;
        }

        return @base.GetTypeField(name) ?? @base.GetBaseField(name);
    }

    internal static PropertyInfo GetBaseProperty(this Type type, string name)
    {
        Type @base = type.BaseType;
        if (@base == null)
        {
            return null;
        }

        return @base.GetTypeProperty(name) ?? @base.GetBaseProperty(name);
    }

    internal static MethodInfo GetInterfaceMethod(this Type type, string name, params object[] args)
    {
        return
            type.GetInterfaces().Select(type.GetInterfaceMap).SelectMany(mapping => mapping.TargetMethods)
                .FirstOrDefault(
                    method =>
                    method.Name.Split('.').Last().Equals(name, StringComparison.Ordinal) &&
                    method.GetParameters().Count() == args.Length &&
                    method.GetParameters().Select(
                        (parameter, index) =>
                        parameter.ParameterType.IsAssignableFrom(args[index].GetType())).Aggregate(
                            true, (a, b) => a && b));
    }

    internal static FieldInfo GetTypeField(this Type type, string name)
    {
        return
            type.GetFields(
                BindingFlags.GetField | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public |
                BindingFlags.NonPublic).FirstOrDefault(
                    field => field.Name.Equals(name, StringComparison.Ordinal));
    }

    internal static PropertyInfo GetTypeProperty(this Type type, string name)
    {
        return
            type.GetProperties(
                BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.Static |
                BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault(
                    property => property.Name.Equals(name, StringComparison.Ordinal));
    }

    // 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");
    }

    MethodInfo method = this._type.GetTypeMethod(binder.Name, args) ??
                        this._type.GetInterfaceMethod(binder.Name, args) ??
                        this._type.GetBaseMethod(binder.Name, args);
    if (method != null)
    {
        // Oops!
        // If the returnValue is a struct, it is copied to heap.
        object resultValue = method.Invoke(this._value, args);
        // And result is a wrapper of that copied struct.
        result = new DynamicWrapper<object>(ref resultValue);
        return true;
    }

    result = null;
    return false;
}

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.

22 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!!

  • https://ma-study.blogspot.com/

  • As usual, great post. You keep amazing me with your content design and layout

  • Awesome dispatch! I am indeed getting apt to over this info, is truly neighborly my buddy. Likewise fantastic blog here among many of the costly info you acquire.

  • I love seeing blog that understand the value of providing a quality..

  • I want you to write good articles like this every day. please don't stop I can't stop reading your articles.

  • Excellent report! I need persons to grasp just how excellent this facts is as section within your posting.

  • As I am looking at your writing, <a href="https://toolbarqueries.google.com.ai/url?sa=t&url=https%3A%2F%2Fwww.mtclean.blog/">majorsite</a> I regret being unable to do outdoor activities due to Corona 19, and I miss my old daily life. If you also miss the daily life of those days, would you please visit my site once? My site is a site where I post about photos and daily life when I was free.

  • Looking at this article, I miss the time when I didn't wear a mask. <a href="https://toolbarqueries.google.com.ag/url?sa=t&url=https%3A%2F%2Fwww.mtclean.blog/">bitcoincasino</a> Hopefully this corona will end soon. My blog is a blog that mainly posts pictures of daily life before Corona and landscapes at that time. If you want to remember that time again, please visit us.

  • I have been looking for articles on these topics for a long time. <a href="https://toolbarqueries.google.co.zw/url?sa=t&url=https%3A%2F%2Fwww.mtclean.blog/">safetoto</a> I don't know how grateful you are for posting on this topic. Thank you for the numerous articles on this site, I will subscribe to those links in my bookmarks and visit them often. Have a nice day

  • I've been searching for hours on this topic and finally found your post. <a href="https://toolbarqueries.google.co.zm/url?sa=t&url=https%3A%2F%2Fwww.mtclean.blog/">casino online</a>, I have read your post and I am very impressed. We prefer your opinion and will visit this site frequently to refer to your opinion. When would you like to visit my site?

  • I will always enter your blog first. to receive new news and you never let me down.

Add a Comment

As it will appear on the website

Not displayed

Your website