private static bool IsAnonymousType(Type type) {
Debug.Assert(type != null, "Type should not be null");
// HACK: The only way to detect anonymous types right now.return Attribute.IsDefined(type, typeof(CompilerGeneratedAttribute), false)
&& type.IsGenericType && type.Name.Contains("AnonymousType") && (type.Name.StartsWith("<>", StringComparison.OrdinalIgnoreCase) || type.Name.StartsWith("VB$", StringComparison.OrdinalIgnoreCase))&& (type.Attributes & TypeAttributes.NotPublic) == TypeAttributes.NotPublic;
}
For a type to be anonymous:
- It should be marked with the CompilerGenerated attribute
- It should be a generic type
- Its name should contain "AnonymousType"
- Its name should start with "<>" or "VB$"
- It shouldn't be publicly accessible
I stumbled upon this beauty while browsing the ASP.NET MVC source (System.Web.Helpers.ObjectVisitor). Because there is no direct way to detect anonymous types yet, I'm pretty sure this is the best implementation out there.
Thanks! That's a good pull!
ReplyDeleteInteresting. One thing I'm curious about, is there a missing || between the <> and VB# checks?
ReplyDeleteThanks for sharing.
Am I missing something, or there's an OR operator missing, when checking if the type name starts with "<>" or "VB$" ?
ReplyDeleteNice catch, must have accidentally removed it formatting the code snippet. Fixed!
ReplyDeleteum... why would I want to do this?
ReplyDeleteThey use it to print friendlier type names in HTML tags.
ReplyDeleteSince we have to pass through every clause to determine if it IS an anonomous type, and therefore, any failure along the way means it definitely isn't, so we can take advantage C#'s if()'s "early-out" by putting the fastest comparisons first.
ReplyDeleteThe "is type.IsGenericType" is probably the fastest (and will also immediately eliminate most classes). The test for non-public is probably the next fastest.
After that, looking at the start of a string is faster that scanning the whole thing, but I have no idea where checking for an attribute comes in sped-wise (I'm gonna guess it's slow).
Putting all that together, we'd get:
return
type.IsGenericType
&& (type.Attributes & TypeAttributes.NotPublic) == TypeAttributes.NotPublic
&& (type.Name.StartsWith("<>", StringComparison.OrdinalIgnoreCase)
|| type.Name.StartsWith("VB$", StringComparison.OrdinalIgnoreCase))
&& type.Name.Contains("AnonymousType")
&& Attribute.IsDefined(type, typeof (CompilerGeneratedAttribute), false);
I have also noticed that Anonymous types have a null namespace. Is there any reason why a type other than an anonymous type would have a null namespace? That is what I am using to detect them, but now I wonder if that is not entirely correct?
ReplyDeleteDid you read this thread: http://stackoverflow.com/questions/4603139/a-c-sharp-class-with-a-null-namespace?
ReplyDelete