User Tools

Site Tools


notes:csharp:anonymoustypes

Anonymous Types and Tuples in C#

  • Tuples - mutable value types
  • Anonymous types - immutable reference types

An anonymous type is an immutable class generated by the compiler. Its definition is inferred from the initializer and its properties are read-only. Consider using an anonymous type for a type that is used in a single method and that contains only trivial properties. The scope of an anonymous type is limited to the method where it is defined.

You can't use an anonymous type as a parameter to a method or as its return value.

Within an assembly, two anonymous objects are of the same type if:

  • they have the same number of properties
  • their properties have the same names and types
  • they appear in the same order
// An object of an anonymous type.
var book1 = new { Title = "AAA", Author = "Author1", Price = 10.99M };
 
// Another object of the same type as book1.
var book2 = new { Title = "BBB", Author = "Author2", Price = 11.99M };

You can also create an array of anonymously typed elements:

var books = new[]
{
    new { Title = "AAA", Author = "Author1", Price = 10.99M },
    new { Title = "BBB", Author = "Author2", Price = 11.99M }
};

Pass an anonymous type (a function) to a generic method.

...
public T CalculateValue<T>(T element, Func<T, T> strategy)
{
    return strategy(element);
}
...
var v = new { A = 1, B = 2 };
var w = CalculateValue(v, p => new { A = p.A+1, B = p.B+1 });

Methods that take a function as a parameter or return a function are called higher-order functions.

Anonymous types are commonly used with LINQ in the select clause of a query expression:

List<Book> books = new List<Book>();
books.Add(new Book { Title = "Title1", Author = "Author1", Price = 10M, IsKindle = false });
books.Add(new Book { Title = "Title2", Author = "Author2", Price = 20M, IsKindle = true });
books.Add(new Book { Title = "Title3", Author = "Author3", Price = 30M, IsKindle = false });
 
// kindleBooks is a collection of objects of an anonymous type { string Title, string Author }
var kindleBooks = from book in books
                  where book.IsKindle
                  // property names from 'book' are projected to an object of the anonymous type
                  select new { book.Title, book.Author };
 
// bookInfo is a collection of objects of an anonymous type { string Info }
var bookInfo = from book in books
               select new { Info = book.Title + ", " + book.Author };
...
class Book
{
    public string Title { get; set; }
    public string Author { get; set; }
    public decimal Price { get; set; }
    public bool IsKindle { get; set; }
}

An anonymous type used as a composite key:

// Group customers by Country and City.
var q = from c in Customers
        group c by new { c.Country, c.City };

Instantiate a tuple containing two integer fields. Note that any tuple containing two integers would be of the same type :

// The type of this tuple is System.ValueTuple<int,int>
var p = (X: 4, Y: 23);
 
// Use the names A and B.
(int A, int B) p2 = p;

Return a tuple from a function:

(int X, int Y) GetPoint(int a, int b)
{
    ...
    return (a, b);
}
...
// Assign the return value to a tuple.
var p1 = GetPoint(1, 2);
 
// Use deconstruction to assign the return values to different variables p and q.
(int p, int q) = GetPoint(3, 4);

The System.ValueTuple generic structures contain methods for

  • equality
  • comparison
  • converting to a string (ToString)

The instantiated System.ValueTuple contains fields Item1, Item2, etc.

Anonymous types vs. tuples:

  • Both anonymous types and tuples are useful to define a storage to hold data but do not define any behaviour.
  • Tuples are preffere for method return types and parameters.
  • Anonymous types are better for composite keys in collections because they are immutable.

Links:

notes/csharp/anonymoustypes.txt · Last modified: 2020/08/26 (external edit)