There is so much new stuff in the upcoming version of .NET, and it’s not just run of the mill components. Microsoft has torqued up .NET and added some very, very powerful features that will significantly change the way you program. These are quantum changes.
In this article, I will demonstrate a small part of my presentation from the West Michigan .NET Users Group Day of .NET, An Introduction to Orcas, anonymous types. (Kudos to Chris Woodruff for pulling off a first rate event.)
Anonymous types (or projections) are a new feature that permits you to define strong types on the fly without writing the nominal—full class—definition. Anonymous types give you the power of strong types, classes defined at design time, without actually having to write that code. Anonymous types are essential for LINQ (Language Integrated Query), and you will find them useful in every day code.
Details That are Useful to Know
Anonymous types are also referred to as projections. (You will see this term used in MSIL (the Microsoft Intermediate Language) if you look at your compiled code with the ILDASM utility.) Anonymous types are types that do not have a formal coded type, a nominal type.
Anonymous types are critical to LINQ because LINQ returns dynamically shaped data whose type is determined by the LINQ query. But, anonymous types are really important for this reason: Anonymous types will let you focus on coding primary domain types specifically, but allow you to not code domain sub-types that are needed only temporarily or just once. Sub-types are usually what are now being referred to as shaped data. For example, given a customer object and address object, sometimes you may want to just want the customer name and address. Anonymous types would permit you to extricate those elements from multiple sources into a dynamic type without a lot of coding beforehand.
Anonymous Types (or Projections) introduce new phrases like data shaping and n-tuples. Data shaping means you organize data into new shapes or organizations. The concept of an n-tuple refers to the number of elements in the anonymous type. For example, an anonymous type with five elements would be referred to as a five-tuple.
Some anonymous type facts include:
- Anonymous types are strongly typed and checked at compile time.
- Code is actually generated and emitted as MSIL for you to support your anonymous types. The name of these types is something like <projection>f__0, but you don’t care.
- Anonymous types have local scope. You can return an anonymous type but callers won’t know the type so you will need Reflection to figure out what’s in there.
Using an Anonymous Type
You can use anonymous types to create random types on the fly (see anon in Listing 1), but it is probably more likely that you will be shaping new types that are some cross section of multiple types (see customerCity in Listing 1, also). The anonymous type declarations are shown in bold. The statements beginning with Dim anon and Dim customerCity demonstrate the syntax for defining anonymous types.
Listing 1: A random anonymous type and a shaped type that is a cross section of a Customer class and an Address class.
Imports System.Collections.Generic Module Module1 Sub Main() 'Randomly defined type Dim anon = new with {.ID = 1, .Name="Paul Kimmel" } Console.WriteLine(anon) Console.WriteLine(anon.ID) Console.WriteLine(anon.Name) Dim address1 As Address = New Address("1313 Mockingbird Lane", _ "Hollywood", "CA", "90201", 1) Dim customer As Customer = New Customer(1, "SoftConcepts", address1) dim customerCity = new with {customer.Name, _ customer.Address.City} Console.WriteLine(customerCity) Console.ReadLine() End Sub Public Class Customer Private _iD As Integer Public Property ID() As Integer Get Return _iD End Get Set(ByVal Value As Integer) _iD = Value End Set End Property Private _name As String Public Property Name() As String Get Return _name End Get Set(ByVal Value As String) _name = Value End Set End Property Private _address As Address Public Property Address() As Address Get Return _address End Get Set(ByVal Value As Address) _address = Value End Set End Property ''' <summary> ''' Initializes a new instance of the Customer class. ''' </summary> ''' <param name="iD"></param> ''' <param name="name"></param> ''' <param name="address"></param> Public Sub New(ByVal iD As Integer, _ ByVal name As String, ByVal address As Address) _iD = iD _name = name _address = address End Sub ''' <summary> ''' Initializes a new instance of the Customer class. ''' </summary> Public Sub New() End Sub End Class Public Class Address Private _address1 As String Public Property Address1() As String Get Return _address1 End Get Set(ByVal Value As String) _address1 = Value End Set End Property Private _city As String Public Property City() As String Get Return _city End Get Set(ByVal Value As String) _city = Value End Set End Property Private _state As String Public Property State() As String Get Return _state End Get Set(ByVal Value As String) _state = Value End Set End Property Private _zipCode As String Public Property ZipCode() As String Get Return _zipCode End Get Set(ByVal Value As String) _zipCode = Value End Set End Property Private _iD As Integer Public Property ID() As Integer Get Return _iD End Get Set(ByVal Value As Integer) _iD = Value End Set End Property
The anonymous types captured by anon and customerCity exist as strong types as if you had defined a class containing an Integer and String—anon—or a class containing two strings—customerCity—created instances, and copied data from the origin types to the new shaped types. Collectively, this is going to save programmers a lot of time because you will no longer need to write nominal definitions for transient types.
Compiling Orcas Code
.NET 3.5 (Orcas) is in beta 1. This means that when you download the beta your installation of Visual Studio, will probably use the default VBC compiler for 2.0. You will need to open a command window and invoke the .NET 3.5 compiler manually. (The good news is that Orcas is scheduled for release this year.)
Here is a sample command line compiler statement that will compile the code represented by Module1 in Listing 1.
C:WINDOWSMicrosoft.NETFrameworkv3.5.20404vbc "C:BooksEarthwebWWW.CODEGURU.COM2007 5-24-2007ExtensionMethods1AnonymousMethodsModule1.vb" /r:Microsoft.VisualBasic.dll /libpath:"C:WINDOWSMicrosoft.NETFrameworkv3.5.20404
In the example, you have specified the path to the VB9 compiler (vbc.exe), the source code, and have included references to the Microsoft.VisualBasic.dll assembly and a library path referring to the .NET 3.5 framework.
Summary
Anonymous types (or Projections) are a means of using strong types that you don’t have to write the code for. Anonymous types are key to data returned from LINQ queries and they will eliminate the need to define named types for every variation on domain types you might need.
Anonymous types may define a new basic, general best practice: Define core domain types in code and everything that is used once or twice, wag at it with an anonymous type.
Work is hard, but we propeller heads are supposed to be smart. So let’s not work so hard; let’s work oh so smart.
About the Author
Paul Kimmel is the VB Today columnist for www.codeguru.com and has written several books on object-oriented programming and .NET. Check out his new book UML DeMystified from McGraw-Hill/Osborne. Paul is a software architect for Tri-State Hospital Supply Corporation. You may contact him for technology questions at pkimmel@softconcepts.com.
If you are interested in joining or sponsoring a .NET Users Group, check out www.glugnet.org.
Copyright © 2007 by Paul T. Kimmel. All Rights Reserved.