Blog - Title

Tuples and Anonymous Types

Tuples and Anonymous Types

  • Comments 8

[Blog Map]  [Table of Contents]  [Next Topic]

Anonymous types are a way that you can define, declare, and instantiate a type and an object in a single step.

This blog is inactive.
New blog: EricWhite.com/blog

Blog TOC
Selection in a LINQ query expression is an operation of projection.  While projecting, you often want to create new types that are used only in the context of projection.  After you have processed the projection, you are not interested in using the types again.  Anonymous types allow you to define a class, and declare, and initialize an object of that class without giving the class a name.

Anonymous types are one of C# implementations of the idea of a tuple.  In computing, a tupple is a set of name/value pairs.  For example, the contents of an address in the Typical Purchase Order XML document could be expressed as:

Name: Ellen Adams
Street: 123 Maple Street
City: Mill Valley
State: CA
Zip: 90952
Country: USA
 

The term tuple originated from the sequence single, double, triple, quadruple, quintuple, n-tuple.  When you create an instance of an anonymous type, it is convenient to think of it as creating a tuple of order n.  If you write a query that creates a tuple in the select clause, then the query returns an IEnumerable of the tuple.

Projection

You often have one set of data and want to create another set of data from it.  You may want to see a subset of the fields.  The data may be filtered so that there is less of it.  The data may be combined with other data to create an entirely new shape of data.  This is called projection.

When you project data, one approach that you can take is to define a new type, and then declare an object (or collection of objects) to hold your projection.  However, often the only purpose to the newly defined type is to hold the projection.  After you have finished processing the projection, you are no longer interested in the type.  It is fairly inconvenient to define the new type just to hold data for a short while.  One interesting solution to this problem is to use an anonymous type.

You create anonymous types using the C# 3.0 object initializer syntax.

A Simple Example

The following shows a very simple example of the creation of an anonymous type:

var x = new
{
    Name = "Eric",
    Phone = "555-1212"
};
Console.WriteLine("x.Name:" + x.Name);
Console.WriteLine("x.Phone:" + x.Phone);
 

When you use an object initializer in this fashion, the C# compiler automatically generates a class with two public properties, Name and Phone.  The compiler infers the types of the two properties.  In this case, they are both of type string.

There is nothing so very special about this type - it is simply an instance of a reference type.  The only thing different about this type is that it has a name that you can't see.

This is a situation where it is required to use the var keyword.  You can't see the name for the type.  But by using the var keyword, we can let the compiler infer the type.

Rest assured that the variable is still strongly typed.  For example, you can't assign it to a variable of an incompatible type.

An Anonymous Type used for Projection

A typical projection would be as follows.  If you have a class Customer (defined using the C# 3.0 automatic properties syntax):

public class Customer
{
    public string Name { get; set; }
    public string Address { get; set; }
    public string Phone { get; set; }
}
 

You could create an anonymous type from this customer, as follows:

Customer c = GetCustomer();
var x = new
{
    Name = c.Name,
    Phone = c.Phone
};
 

However, you can be even terser.  C# 3.0 supports a projection style object initializer.  If you want the anonymous type to have the same property names as the class from which you are projecting, then you can omit the assignment, like so:

Customer c = GetCustomer();
var x = new
{
    c.Name,
    c.Phone
};
 

This is permitted so long as the property expression in the initializer ends in a name.  If the property expression does not end in a name, then you must use the syntax "PropName = expr".  The following is not permitted:

var z = new {
    c.Name,
    "425-555-1212"
};
 

Instead, you would have to write:

var z = new
{
    c.Name,
    Phone = "425-555-1212"
};
 

Projection of a Collection

When coding in the functional style, you will often take one collection of a type, and project a new collection of a different type.  Consider the following code, which takes a collection of Customer objects, and projects an anonymous type.  The code uses the Select extension method, which is what we use when we want to project a collection of a different type.  The following code is attached to this page:

public class Customer
{
    public string Name { get; set; }
    public string Address { get; set; }
    public string Phone { get; set; }
}
 
class Program
{
    static void Main(string[] args)
    {
        Customer[] custList = {
            new Customer {
                Name = "Bob",
                Address = "123 Main Street, Seattle, WA 98111",
                Phone = "555-1234"
            },
            new Customer {
                Name = "Bill",
                Address = "555 Center Street, Tacoma, WA 97158",
                Phone = "555-9999"
            }
        };
 
        var newCustList =
            custList.Select(
                c => new
                {
                    UCName = c.Name.ToUpper(),
                    UCAddress = c.Address.ToUpper()
                }
            );
 
        foreach (var c in newCustList)
            Console.WriteLine(c.UCName);
    }
}
 

Scoping of Anonymous Types

One point that is important to make is that anonymous types (and collections of them) are limited to local scope.  This, of course, should be clear based on the semantics of C# - if you want to return an object from a method, you must declare the method to return an object of that type.  But if you are using an anonymous type, you can't declare the method to return such a type.  Once you want to use an object outside of a method, you must make it a nominal type.

If you have an object (or collection of objects) of an anonymous type that you want to use outside of a method, the approach to take is to define a nominal type with appropriate scope, and rewrite your code to project your nominal type.

The C# specification states that if you have two instances of an anonymous type such that all of their properties are named the same, the properties are in the same order, and the types of each of the properties are identical, then the two anonymous objects have the same type.  You can use this characteristic of anonymous types to implement some useful idioms in local scope.  For instance, this allows you to create two queries that both result in a collection of anonymous types, and if they are the same, you can concatenate the results.  The following code shows this.  The code is attached to this page.

int[] collection1 = new[] { 1, 2, 3 };
int[] collection2 = new[] { 4, 5, 6 };
 
var q1 =
    from i in collection1
    select new
    {
        FromCollection = 1,
        Value = i
    };
 
var q2 =
    from i in collection2
    select new
    {
        FromCollection = 2,
        Value = i
    };
 
var q3 = q1.Concat(q2);
 
foreach (var v in q3)
    Console.WriteLine(v);
 

Using the facility that anonymous types have a pretty good ToString method, this example produces the following output:

{ FromCollection = 1, Value = 1 }
{ FromCollection = 1, Value = 2 }
{ FromCollection = 1, Value = 3 }
{ FromCollection = 2, Value = 4 }
{ FromCollection = 2, Value = 5 }
{ FromCollection = 2, Value = 6 }
 

There are techniques where you can take advantage of knowledge of the compiler implementation to allow anonymous types to escape from local scope.  I've seen such types hanging out in lower downtown Seattle.  They start drinking wine in the morning, smoking crack, and mugging people.  For their own good (and ours), keep them in local scope.

[Blog Map]  [Table of Contents]  [Next Topic]

Attachment: TuplesAndAnonymousTypes.cs
Leave a Comment
  • Please add 6 and 7 and type the answer here:
  • Post
  • "The above is commonly referred to as a 5-tuple."

    If I am not wrong, it should be "6-tuple".

    BTW... Thank you very much for thsi tutorial. Very helpful.

    Cheers,

    Pravin

  • " If the property expression does not end in a name, then you must use the syntax "PropName = expr". The following would not be permitted:"

    Can we see an example of a property expression that doesn't end in a name?

    michael.isbell@gmail.com

  • It is possible to return an anonymous type out of a function using some inference tricks.  However you must pass in an instance of that type to get the code to work properly.  For instance here is a post detailing how to cast to an anonymous type type.  It's in VB but the same principal applies to C#.

    http://blogs.msdn.com/jaredpar/archive/2007/10/01/casting-to-an-anonymous-type.aspx

  • I understand that it is possible to get anonymous types to leak out of local scope. However, my new favorite approach is to use classes that have a certain number of automatic properties. The syntax is minimal - if you have a 6-tupple, it takes 8 lines of code. Further, you have the option of writing a constructor if you need one for some reason or other. And lastly, it is strongly typed. I used this approach in my most recent prototypes of a LINQ to XML programming interface to Open XML documents, elsewhere on this blog.

  • In a previous post, I introduced Get-RecordedTV , which was built upon another function, Search-WindowsDesktop

  • "Selection in a LINQ query expression is an operation of projection." ??? Sure selection is different from projection; are LINQ designers familiar with relational algebra? Here is how to transform a list of strings to a list of string lengths. Take an (unary) relation, say

    strings = {str="a", str="abc"}

    join it with a predicate that couples a string with its length, then project away the unwanted "str" column. In SQL

    select strlen(str) from strings

    The bottom line: what you call "projection" is actually a join.

  • Hi Tegiri,

    One piece of background about LINQ is that it was intended to be somewhat similar to SQL, although the mechanism is completely different, and there are important differences in capabilities and syntax.  I think it was felt that similarity to SQL would provide some level of familiarity to the existing community of SQL developers.  And in the case of LINQ to SQL and LINQ to Entities, the similarities to SQL prove even more valuable.

    This is why they chose to use Select as the projection operator.  Just to be clear about what I mean: projection is the operation of taking some collection of type T, and 'projecting' a new collection of type T1.  In the case of elaborate queries, the collection of type T1 is then 'projected' into a collection of type T2, and so on.

    In contrast, joining is the operation of taking two related data sources, and 'projecting' a single collection from the two.

    To use your example, projecting a collection of string lengths from a collection of strings can be accomplished like this:

    var strings = new[] { "a", "abc" };

    var stringLengths = strings.Select(s => s.Length);

    Does this make sense?

    -Eric

  • "For their own good (and ours), keep them in local scope."

    Still, seems like a shame that I can't have truly anonymous typing and return them from functions:

    public { bool , int } TryParse( string input , int? default )

    {

     try

     {

       return { true , Int32.Parse(input) };

     }

     catch

     {

       return { false , default || 0 };

     }

    }

    public void DoStuff()

    {

     bool b;

     int x;

     (b,x) = TryParse( "100" );

     if(b)

       Console.WriteLine( x );

     else

       Console.WriteLine( "No" );

     (b,x) = TryParse( "foo" );

     if(b)

       Console.WriteLine( x );

     else

       Console.WriteLine( "No" );

    }

    TryParse is the only example I could think of aside from the classic swap:

    public void DoStuff()

    {

     MyObject a = new MyObject("foo");

     MyObject b = new MyObject("bar");

     (b,a) = (a,b);

    }

    Philosophically I see no rational or logical reasoning (aside from "it's always been like that") why round-brackets can be used to type and group inputs to a function but not to return from a function. Imagine instead a universe where functions could only ever accept single parameters too, we'd be forever doing the following:

    public class DoSomethingArgs

    {

     public int someParam;

     public string someOtherParam;

    }

    public bool DoSomething( DoSomethingArgs )

    {

    ...

    }

    but the above is NOT normal, some of us think the left-side of functions and operators should be parameterisable too!

Page 1 of 1 (8 items)