Simplifying LINQ: Object Initialization, Type Inference, Anonymous Types

by Chad 6. April 2009 18:46

Welcome back! This is the second post in my 'Simplifying LINQ' series of weblog posts. If you missed my first post on Lambda Expressions, check it out here. It's not required for this post, so if you're not interested just keep on reading.

In this post I'm going to cover some features that were introduced with the release of the 3.0 version of the .NET framework. These features enable the code patterns that make LINQ so enjoyable. They are: Object Initialization, Type Inference, and Anonymous Types.  My goal here is to take the "magic" away from these new concepts by showing how they evolved from concepts that a developer comfortable with .NET 2.0 is already familiar with.  Although the syntax has changed, each of these concepts actually compile to code that you already know.  I think that the best way to illustrate this is by showing a code sample using the new syntax, then comparing it to the compiled output (reflected with .NET Reflector.)

Object Initialization

Object Initialization allows you to initialize an object's properties when you instantiate it. This is useful for when an overloaded constructor isn't available or when creating projections in a LINQ query.

C# Syntax

MyRectangle objectInitialization

    = new MyRectangle() { Height = 2, Width = 4 };

Compiled Output

MyRectangle <>g__initLocal0 = new MyRectangle();

<>g__initLocal0.Height = 2;

<>g__initLocal0.Width = 4; 

You should notice that this one line of code actually gets compiled to the three lines of code that you had to write before object initialization. Instantiate your variable, set the Height property, and set the Width property. 

Type Inference

With Type Inference, the compiler will infer a variable's type based on the value being assigned to it.

C# Syntax

var myString = "Text"; // Type=String

Compiled Output

string myString = "Text";

In this example, the compiler knew that myString was of type String because a string literal was assigned to it. In the compiled code, "var" is replaced by the actual type "string".

Warning: Don't let yourself fall into the trap that Type Inference sets up. It is NOT a convenience keyword for rapid application development.  I know it's tempting to type "var" when your class name is 15+ characters long, but don't do it (at least in production code.) In some situations, this could cause unexpected bugs that wouldn't necessarily be caught by the compiler.  The reason for and appropriate use for the var keyword is when the type is not statically know, such as with Anonymous Types.

Anonymous Types

Anonymous types use syntax that instructs the compiler to define a class at compile time.  Since the class is created by the compiler at compile time, you as the developer have no way of statically knowing the name of the class because it hasn't been created yet - "var" acts as a placeholder for the type that will be created by the compiler.

C# Syntax

var anonymous = new { FirstName = "Chad", LastName = "Boschert" };

Compiled Output...

<>f__AnonymousType0<<FirstName>j__TPar, <LastName>j__TPar> anonymous

    = new <>f__AnonymousType0("Chad", "Boschert");

Notice that var is replaced by the type  <>f__AnonymousType0<<FirstName>j__TPar, <LastName>j__TPar>. That class definition is below.

...and new class definition

[DebuggerDisplay(@"\{ FirstName = {FirstName}, LastName = {LastName} }", Type="<Anonymous Type>"), CompilerGenerated]

internal sealed class <>f__AnonymousType0<<FirstName>j__TPar, <LastName>j__TPar>

{

    // Fields

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]

    private readonly <FirstName>j__TPar <FirstName>i__Field;

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]

    private readonly <LastName>j__TPar <LastName>i__Field;

 

    // Methods

    [DebuggerHidden]

    public <>f__AnonymousType0(<FirstName>j__TPar FirstName, <LastName>j__TPar LastName);

    [DebuggerHidden]

    public override bool Equals(object value);

    [DebuggerHidden]

    public override int GetHashCode();

    [DebuggerHidden]

    public override string ToString();

 

    // Properties

    public <FirstName>j__TPar FirstName { get; }

    public <LastName>j__TPar LastName { get; }

}

The compiler-generated class code from .NET Reflector may not be very readable. It basically defines a class with two public string getter properties for FirstName and LastName and a constructor taking two string parameters for FirstName and LastName. The simple syntax of new { Prop = val } does a lot of the footwork that you used to have to do by hand.

Final Thoughts

Hopefully these code examples have illustrated what is actually happening when you use these new language features. Loosely speaking, there is nothing new other than syntax. (Although, I'm sure someone on the language team or compiler team at Microsoft would disagree with me.)  We're still just constructing types and setting property values.

Of course the best way to learn something is to play with it. Write some sample code, build it, and look at it in .NET Reflector. These samples require Visual Studio 2008 (Express should work,) and the .NET 3.0 Framework.

Tags: , ,

Simplifying-LINQ

Comments are closed

Powered by BlogEngine.NET 1.5.0.7
Theme by Mads Kristensen

About the author

Chad

Meeeee!!!

Hi, my name is Chad Boschert and I'm a software developer in Springfield, Missouri. I've been developing .NET applications in C# since 2002.

Recent Comments

Comment RSS

Calendar

<<  May 2013  >>
MoTuWeThFrSaSu
293012345
6789101112
13141516171819
20212223242526
272829303112
3456789

View posts in large calendar