Anonymous Types in Query Expressions

This introductory level post covers a new LINQ feature in C# 3.0 called anonymous types. I'll focus on explaining when you might want to use an anonymous type, and when it might be more useful to use a specific type instead of an anonymous type.

Using Anonymous Types

Consider the following simple class:

     class Customer
    {
        public string Name { get; set; }
        public int Age { get; set; }        
    }

Let's imagine populating a List<Customer> (pronounced "list of customer") called CustomerList with a few rows of data:

{ Name = A, Age = 0 }
{ Name = B, Age = 1 }
{ Name = C, Age = 2 }
{ Name = D, Age = 3 }
{ Name = E, Age = 4 }

We can now run a simple LINQ query expression against the data in the CustomerList:

     var query = from c in CustomerList
                where c.Name != "B"
                select new { Name = c.Name, Age = c.Age };

This query returns the set of records in the CustomerList that are not named "B:"

{ Name = A, Age = 0 }
{ Name = C, Age = 2 }
{ Name = D, Age = 3 }
{ Name = E, Age = 4 }

See Listing 0 for the complete code for this simple program.

Listing 0: A simple LINQ program that uses an anonymous type

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    class Customer
    {
        public string Name { get; set; }
        public int Age { get; set; }        
    }
    
    class Program
    {
        static void Main(string[] args)
        {            
             // Populate the CustomerList
            var CustomerList = new List<Customer> 
            {
                new Customer { Name = "A", Age = 0 },
                new Customer { Name = "B", Age = 1 },
                new Customer { Name = "C", Age = 2 },
                new Customer { Name = "D", Age = 3 },
                new Customer { Name = "E", Age = 4 }
            };

            // Query the CustomerList
            var query = from c in CustomerList
                        where c.Name != "B"
                        select new { c.Name, c.Age };     
             // Write the output from the query to the console
            foreach (var q in query)
            {
                Console.WriteLine(q);                
            }

         }
    }
}

When processing the query in Listing 0, the compiler creates an anonymous type in response to this code found in the select line:

new { c.Name, c.Age };

The absence a type name between the word new and the first open curly brace tells the compiler to create an anonymous type. In response to this code, the compiler works behind the scenes to mock up an anonymous object for you. The object might look something like this:

     class SomeAnonymousUnknownName
    {
        public string Name { get; set; }
        public int Age { get; set; }
    }

An instance of this class is created behind the scenes for each member of the IEnumerable<T> collection returned by the query. The exact name of this anonymous type cannot be known by the programmer.

This is usually exactly what you want, and you will be pleased with the the easy to use syntax that tells the compiler to generate an anonymous type for you. However, there are occasions when you want to have more control over your anonymous class.

Returning a Particular Class from a Query Expression

In some cases you might wish there were additional methods or properties on the class returned from a query expression. You could use these methods to perform explicit calculations on the data in each instance of your class. To enable this functionality, you can create your own class, give it a name, and have the query expression that you create return it for you. Consider the code shown in Listing 1.

Listing 1: The query shown in this program returns not an IEnumerable<T> where T is some anonymous type, but rather an IEnumerable<Customer>.

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    class Customer
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public int CalcResult() { return 5 * Age; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var CustomerList = new List<Customer> 
            {
                new Customer { Name = "A", Age = 0 },
                new Customer { Name = "B", Age = 1 },
                new Customer { Name = "C", Age = 2 },
                new Customer { Name = "D", Age = 3 },
                new Customer { Name = "E", Age = 4 }
            };

            var query = from c in CustomerList
                        where c.Name != "B"
                        select new Customer { Name = c.Name, Age = c.Age };

            foreach (var q in query)
            {
                Console.WriteLine("{0} {1} {2}", q.Name, q.Age, q.CalcResult());
            }

        }
    }
}

The output from this program would look like this:

 A 0 0
C 2 10
D 3 15
E 4 20

In Listing 1 there is no anonymous type. Instead, the query expression returns an IEnumerable<Customer> with the names of the fields you want to populate explicitly called out:

select new Customer { Name = c.Name, Age = c.Age };

The code in the foreach loop is able to access a specific method of class Customer called CalcResult. If you wanted to add other methods or properties to the Customer class, you could do so, and you could then call these methods in your foreach loop. This would be difficult to do with an anonymous type because you do not know its name.

Querying a Class You Can't Modify

Suppose you had a class called Customer that did not have a CalcResult method. Suppose further that you could not modify the class either because you did not have its source or for some other reason:

     class Customer
    {
        public string Name { get; set; }
        public int Age { get; set; }        
    }

In this situation it would be difficult to perform an action on each instance of the class as you did with the CalcResult method in Listing 1.

To resolve this problem you can create a descendent of the Customer class, add your CalcResult method to it, and then create an instance of that class in your query expression. An example of this type of code is shown in Listing 2.

Listing 2: By creating a descendant of Customer called MyCustomer, you can return a specialized class from a query expression that has traits not found in the class you are querying.

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    class Customer
    {
        public string Name { get; set; }
        public int Age { get; set; }        
    }

    class MyCustomer : Customer
    {
        public int CalcResult() { return 5 * Age; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var CustomerList = new List<Customer> 
            {
                new Customer { Name = "A", Age = 0 },
                new Customer { Name = "B", Age = 1 },
                new Customer { Name = "C", Age = 2 },
                new Customer { Name = "D", Age = 3 },
                new Customer { Name = "E", Age = 4 }
            };

            var query = from c in CustomerList
                        where c.Name != "B"
                        select new MyCustomer { Name = c.Name, Age = c.Age };

            foreach (var q in query)
            {
                Console.WriteLine("{0} {1} {2}", q.Name, q.Age, q.CalcResult());
            }

        }
    }
}

This code once again allows you to call a CalcResult method, or to add any other code you might wish to the class you are querying. It is interesting to note that this query returns an IEnumerable<MyCustomer> even though the data source is a List<Customer> .

Summary

In this post readers who are still new to LINQ have had a chance to think about anonymous types and how they are used in a simple LINQ program. Some readers might find a use for the specific solutions outlined in this post; others will hopefully have found it useful to simply think about anonymous types and how they are used in LINQ query expressions.