Detecting anonymous types on Mono

June 24th, 2011

Little more than a week ago, I sat down to add the possibility of using anonymous types as models for views in Nancy. Now, since not all view engines can handle anonymous types as their model I decided I would intercept them, along the way to the view engine, and convert them into an ExpandObject instead.

In order to do this I needed to detect them first, and after poking around the reflection API, and use Google + Twitter to confirm it, I came to the conclusion that there is nothing in there that will tell me if the instance I have is of an anonymous type or not.

Then I got a tweet from Joseph Gray, also known at @MrJosephGray on Twitter, sent me a link to a blog post by Jef Claes titled Checking for anonymous types and it contained just what I needed. It works beautifully, until I ran my code on Mono that is.

Even though the blog post is not clear on it, I was aware of that the detection method relies on undocumented naming conventions and no guarantee that any of the traits, that it checks, won’t be changed in the future by Microsoft. That is also why I was not surprised that there were issues while running it on Mono.

After taking the debugger out for a quick spin it was evident that it was the type name that was the culprit. On Mono (at least on 2.10 that I am running), the name of the generated type contains AnonType and not AnonymousType and it was a trivial task to patch the extension method to check for that as well.

The full implementation that I am using in Nancy is listed below

using System;
using System.Reflection;
using System.Runtime.CompilerServices;

/// <summary>
/// Contains miscellaneous extension methods.
/// </summary>
public static class Extensions
{
    /// <summary>
    /// Checks if the evaluated instance is an anonymous
    /// </summary>
    /// <param name="source">The object instance to check.</param>
    /// <returns><see langword="true"/> if the object is an anonymous type; otherwise <see langword="false"/>.</returns>
    public static bool IsAnonymousType(this object source)
    {
        if (source == null)
        {
            return false;
        }

        var type = source.GetType();

        return type.IsGenericType
               && (type.Attributes & TypeAttributes.NotPublic) == TypeAttributes.NotPublic
               && (type.Name.StartsWith("<>", StringComparison.OrdinalIgnoreCase) || type.Name.StartsWith("VB$", StringComparison.OrdinalIgnoreCase))
               && (type.Name.Contains("AnonymousType") || type.Name.Contains("AnonType"))
               && Attribute.IsDefined(type, typeof (CompilerGeneratedAttribute), false);
    }
}
view raw Extensions.cs This Gist brought to you by GitHub.

Andreas Håkansson

  • Jason Grundy

    Aren’t you missing a parenthesis wrapping the two sides of the “or” condition in this line:

    && type.Name.Contains(“AnonymousType”) || type.Name.Contains(“AnonType”)

  • http://twitter.com/TheCodeJunkie TheCodeJunkie

    You are perfectly correct, thank you! I’ve updated the gist on github, let’s see if it will reflect here shortly or I will edit the post!

  • Jef Claes

    Thanks for the mention. Glad someone could actually use it in production code ;)

blog comments powered by Disqus