Microsoft & .NETVisual BasicAnonymous Types (or Projections) in VB9

Anonymous Types (or Projections) in VB9

Developer.com content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.

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.COM20075-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.

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Latest Posts

Related Stories