Declaring Anonymous Types in VB

Introduction

Using an anonymous type means that the compiler will code generate a class for you based on context and named initializers. This article introduces you to anonymous types and explores some of the variations of their usage.

I am not lazy by nature; the converse is actually true. I personally spend hundreds even thousands of hours at my craft, but when it comes to solving problems time is money. When I'm learning then I don't mind tickling an idea to determine all of the myriad of ways in which it can be solved. In practice I use the cheapest, most direct, and practical approach that meets this test: reasonableness and sufficiency.

I write a dozen classes a week. I re-write some classes over and over throughout the years to discover the optimal solution. In practice though I borrow my own code, the code of others, or use code generators and tools to get the job done. Some 'bosses' may want to feel that we programmers are working hard, but the smart boss will want you to work smarter not harder. Working smarter means that you leverage all of the tools and resources available for optimal results. In Visual Basic, in some contexts, anonymous types provide reasonable and sufficient solutions and satisfy the optimal use of time.

Defining an Anonymous Type

An anonymous type quite simply means that you don't specify a class ahead of time. All you do when you use an anonymous type is to specify the named fields and values; the compiler then writes the class for you. Letting the compiler write your classes is a great labor saver. Imagine no syntax errors, no class to debug, and being left with usable results.

If you interviewed the inventor of anonymous types and asked why were these invented you might get a variety of answers. One answer might be anonymous types help when you are using LINQ. A simple answer plain for all to see is that for years programmers had to specify every single class by hand and this is labor intensive. Clearly many classes have historically been written and may only be used one time. Suppose for example that you have a customer and contact information class. Further suppose that you want to display a customer name and phone number to display this information in a pick list or report. Some programmers-including me in the past-have defined a composite class with containing the desired bits of information. Accumulatively all of these kinds of classes add up to a significant amount of time over a project and career. The anonymous type-and technologies like LINQ-eliminate the need to write these kinds of classes.

An anonymous type is defined by using the Dim keyword, a variable name, followed by the assignment operator, the New With construct, and a list of field names and values. Think of it as stenography for programmers. Here is a very short anonymous type definition that defines a simple company class.

Dim company = New With { .CustomerID = "ALFKI", .CompanyName = "Alfreds 
Futterkiste"}

When the compiler encounters the preceding code it interprets this code as you wanting a class and code. It then generates one for you. From this point you can use the object company and modify CustomerID and CompanyName just as if you had written the class yourself.

Note: CodeRush is a meta-programming tool that writes code using pre-existing templates and a two or three shortcut key combination.

Arguably you could use a great tool like CodeRush and the labor involved in writing the class yourself is less labor intensive than writing all of the code keystroke by keystroke, but think of the anonymous types as and an evolutionary progression from manually writing the code-to using meta-programming tools CodeRush-to using a shorter notation. (A neat benefit of CodeRush is of course that you can iteratively define new CodeRush templates that spit out user-defined templates. This means now that the anonymous type exists and you can define a CodeRush template for it. In this way programmers, learning new idioms and using tools like CodeRush can stay hyper-productive.)

The anonymous type shown earlier generates a class as if you had written it yourself. You can verify this with a tool like Red-Gate's Reflector. Here is the long-hand version of the customer class, but really who wants to go to all the trouble for every single class (see Listing 1).

  Public Class Customer
          Public Sub New()
  
          End Sub
  
          Public Sub New(ByVal CustomerID As String)
              FCustomerID = CustomerID
          End Sub
  
          Private FCustomerID As String
          Public Property CustomerID() As String
              Get
                  Return FCustomerID
              End Get
              Set(ByVal Value As String)
                  FCustomerID = Value
              End Set
          End Property
  
          Private FCompanyName As String
          Public Property CompanyName() As String
              Get
                  Return FCompanyName
              End Get
              Set(ByVal Value As String)
                  FCompanyName = Value
              End Set
          End Property
  
          Public Overrides Function ToString() As String
  
              Return String.Format("CustomerID={0}, CompanyName={1}", _
                                   FCustomerID, FCompanyName)
          End Function
  
  
      End Class

Listing 1: The Customer class long-hand.

There are benefits to anonymous types in addition to saving you time. For instance, every application is comprised of classes. These classes make up the model that represents your system. The more classes there are the more complex your model is. You don't have to model anonymous types. Generally anonymous types are temporal. Excluding piddling classes from your system--or the model of your system--makes it easier for other developers to jump on board more quickly. And, if you are working on a disciplined team then of course classes you don't write save you time managing the model of your system. Saving time writing, modeling, and learning a system saves a significant amount of time accumulatively.

Declaring Anonymous Types in VB

Specifying a Key

Anonymous types support defining a key too. Every field in an anonymous type is readable and writable by default. You can specify that a field is the key. The key field is immutable as all such keys should be. The following code demonstrates how to employ the Key keyword.

Dim company = New With {Key .CustomerID = "ALFKI", .CompanyName = "Alfreds 
Futterkiste"}

In the revised version CustomerID is immutable. CustomerID will always be the value assigned upon initialization. If you check Reflector you will see that this is enforced in the generated code (see Figure 2).

[customerid.jpg]
Figure 2: Note that CustomerID only has a getter and the CustomerID field is private as it should be.

Calling Parameterized Constructors and Using Named Initializers

If you have a pre-defined class, but want to use the initialize approach for fields that aren't defined in the constructor then you can combine a parameterized constructor with named initializers. (I am not using an anonymous type for this example.) Using the Customer class in Listing 2, the statement below calls the constructor that accepts a CustomerID and provides values for other public properties using the initialize list.

  Dim company3 As New Customer("PAULK") With {.CompanyName = "Kimmels 
  Konfections"}

If you step into the statement then you will see that it calls the Sub New(ByVal CustomerID As String) constructor and that the public property CompanyName is initialized too. Initalizers are supported for anonymous types and user- defined types.

Using Fields as Initializers

You also have the option for using earlier fields in initialize lists. For example, if the CompanyName-in our scenario-is identical to the CustomerID then you can provide a value for CustomerID and use the CustomerID to initialize the CompanyName. Here is the syntax for doing so.

Dim company4 As New Customer With {.CustomerID = "PAULK", .CompanyName = 
  .CustomerID}

In this example, I am using the named type Customer and setting CompanyName to CustomerID. Using fields in your initializer list is supported for anonymous types and user- defined type instantiation as shown above. Let's return to anonymous types.

Defining Nested Anonymous Types

Just as you can define composite types--classes containing fields that are other classes--long-hand, you can define anonymous types with nested types. To do so you use the initialize approach list and nest the initialization sequence. The following statement demonstrates this.

  Dim company5 = New With {.CustomerID = "PAULK", _
    .CompanyName = "Kimmel's Konfections", _
    .Phone = New With {.Number = "(517) 555-1212"}}

In the example notice that I have defined company5 as an anonymous type with three fields: CustomerID, CompanyName, and Phone. The difference here is that Phone is an anonymous type too. Simply repeat the usage of the "New With" construct for the nested type and provide the initializer list for the nested type. In this example the compiler will properly code generate two anonymous classes, one representing the outer type and the other representing the nested type. The nested type will be used as the type of the class property.

Summary

If one is performing a task then lazy is a relative term. The simple fact of using the easiest, sufficient approach does not make one lazy. I encourage you to use anonymous types wherever suitable. Think of anonymous types as a short hand for class syntax.

Biography

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 upcoming book Professional DevExpress ASP.NET Controls (from Wiley) now available on Amazon.com and fine bookstores everywhere. Look for his upcoming book Teach Yourself the ADO.NET Entity Framework in 24 Hours (from Sams). You may contact him for technology questions at pkimmel@softconcepts .com. Paul Kimmel is a Technical Evangelist for Developer Express, Inc, and you can ask him about Developer Express at paulk@devexpress.com and read his DX blog at http:// community.devexpress.com/blogs/paulk.



Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • With JRebel, developers get to see their code changes immediately, fine-tune their code with incremental changes, debug, explore and deploy their code with ease (both locally and remotely), and ultimately spend more time coding instead of waiting for the dreaded application redeploy to finish. Every time a developer tests a code change it takes minutes to build and deploy the application. JRebel keeps the app server running at all times, so testing is instantaneous and interactive.

  • On-demand Event Event Date: March 27, 2014 Teams need to deliver quality software faster and need integrated agile planning, task tracking, source control, auto deploy with continuous builds and a configurable process to adapt to the way you work. Rational Team Concert and DevOps Services (JazzHub) have everything you need to build great software, integrated seamlessly together right out of the box or available immediately in the cloud. And with the Rational Team Concert Client, you can connect your …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds