Tuples are popular choices in other programming languages for tightly-scoped data containers. One drawback of tuples is that items within the tuple are referenced by a numerical position rather than a name much like an array.
Anonymous types give some of the convenience of tuples but with the ability to name the items contained within it. The trade-offs are that an anonymous type is not interchangeable with named types or with anonymous types from other assemblies (within one assembly, the same property names and types in the same order share one type) and that the type has no name you can refer to directly (but you can indirectly using generics).3
Code
var contacts = db.Customers.Select(c => new { c.Name, c.Email });
foreach (var contact in contacts)
Console.WriteLine(contact.Name + "\t" + contact.Email);var contacts = db.Customers.Select(c => new Contact { Name = c.Name, Email = c.Email });
foreach (var contact in contacts)
Console.WriteLine(contact.Name + "\t" + contact.Email);
// ...
class Contact
{
public string Name { get; set; }
public string Email { get; set; }
}Notes
- The compiler will create a class named
<>f__AnonymousType0(and so on) for each anonymous type - Anonymous type properties are read-only, and the compiler generates value-based
Equals,GetHashCodeandToString - Anonymous types are often used in LINQ
Selectstatements to "project" a final structure:
1 LINQ providers only understand the query and the lambda expressions. Using this kind of projection tells them what fields they need to retrieve (they can not look at other code as it is compiled).
2 You can project into other classes but really only as the last operation in the query. Some providers can follow the assignment through other classes mid-query if you use initializer syntax but many do not. Using a constructor mid-query will almost certainly fail or result in wrong behavior.
3 If you want to share a type across methods or assemblies you can use Tuple.Create (.NET 4), at the expense of giving up names for Item1, Item2 etc., or Tuples C# 7.0 which keep the names. Alternatively you can make your method generic and have the parameter be the generic type - the runtime will take care of ensuring the method is created with the correct anonymous declaration.