A lady can become a lady only if her mother has teached her everything a proper lady should know. Obviously the mother should learn that stuff from grandparents.
In this context, grandmother is Generics and grandfather is Linq. Surprisingly enough, they engendered a wacky abstraction of Anonymous Types, a great facilitator of data filtering. They teached it how to stroll, how to smile and how to say "no" politely.
The mechanism of genetic inheritance has worked out well, so anonymous types are also generic internally: the code
var a = new { Name = "Кастусь" };
var b = new { Position = "Developer" };
var c = new { Name = "Пятрусь", Position = "Developer" };
brings up the following IL:
Naming convention.
Now we can make some assumptions about the naming. Most likely, angle brackets have been chosen because you can’t put them in a class name from C# (no idea about the f__ part though). The AnonymousType part is followed by the type order number and then goes `1 or `2 that is a standard IL for the amount of parameters of a generic type [1].
But wait, asks the careful reader, why are they generic in the first place? Why can’t we go with strings and other nice data structures out there? Answer: it’s done to reduce the amount of anonymous types that are actually created [2]. Try the following code:
var a = new {A = "foo", B = 12};
var b = new {A = DateTime.MinValue, B = false };
Console.WriteLine(a.GetType() + "\n" + b.GetType());
And you'll see we have only one (!) generic type under the murky waters of IL. As long as the names and the order of parameters is the same, the same generic type can be used to create the instances.
Power(less) of anonymous types.
Luckily, anonymous types can’t be used outside of a method: they can't be returned from a method and can't be passed into as parameters - unless they are boxed into an object. ASP.NET MVC heavily uses anonymous types and reflection to go through the fields.
Technically, to address that boxing penalty, you can use a technique called casting by example. But it's so spooky that I'm not even going to present it here. For educational purposes, you can type "casting by example" in your favorite browser and read on.
But never use it.
Another not-so-spooky idea is creating a generic list of anonymous types:
var customer = new { Name = "John" };
var list = (new[] { customer }).ToList();
list.Add(new { Name = "Bill" });
I'm not yet sure if this is worth using in production. I did that once, and later we refactored the code to something more explicit. By and large, a general advice is to use anonymous types for some extremely simple queries. They just don't scale further, at least for now.
How to identify the anonymous.
var me = new {Name = "Andrew", City="Prague"};
The C# code above brings up the following auto generated beast (generic, internal, sealed, compiler generated type with an ugly name):
Since there’s no IsAnonymous metadata flag, we seem to have to write something like this:
private static bool IsAnonymous(Type type)
{
return type.IsGenericType
&& Attribute.IsDefined(type, typeof(CompilerGeneratedAttribute))
&& type.Name.Contains("AnonymousType")
&& (type.Name.StartsWith("<>") )
&& (type.Attributes & TypeAttributes.NotPublic) == TypeAttributes.NotPublic
&& (type.Attributes & TypeAttributes.Sealed) == TypeAttributes.Sealed;
}
That’s pretty much it.
In the next post we’d finally talk about the lady.
Footnotes.
[1] – Read about The Story of the Tick Sign here or listen to it on DotNetRocks! - it's hilarious and hortatory.
[2] – I’ve already posted a word or two about immutability of anonymous types, and there's an article about VB.NET that explains the idea of IL sharing in a greater detail.