views:

378

answers:

2

I am a beginner who finally started understanding anonymous types.

(see old post http://stackoverflow.com/questions/3010147/what-is-the-return-type-for-a-anonymous-linq-query-select-what-is-the-best-way-t)

So in LINQ queries you form the type of return value you want within the linq query right? It seems the way to do this is anonymous type right?

Can someone explain to me if and when I could use a Tuple/Expando object instead? They all seem very simliar?

+3  A: 

Tuples and Expando objects are not normally used in LINQ. They're both quite different than anonymous types.

Anonymous types are commonly used to "shape" LINQ queries; for example, you can define a type that has a string Name property and an int Age property.

Tuples are types that only act as "pair" or "triplet" kinds of structures. For example a Tuple<string, int> can be defined, but the names of the properties are named Item1 and Item2, not Name and Age. Tuples are not normally used to shape LINQ queries because these property names make the code less clear.

ExpandoObject is totally different. It allows you to add properties at runtime to an existing object.

Stephen Cleary
Ok that helps thanks. What are the advatages of a tuple over anonymous ? Im guessing it has something to do with you can't use anonymous types outside of the method? or something? Expandoobject seems to me related to the dynamic type which has nothing to do with linq queries... tought perhaps if I am getting a linq query of customer and I want to add a 'rating' integer to the customer class I would use expando/dynamic? That be a reason to use it maybe?
punkouter
It's true that tuples can be used anywhere, while anonymous types are restricted to the method. It's more common, though, to define your own result type with meaningful field names.ExpandoObject is one type of dynamic object; while it can be used in LINQ queries (just like Tuple types), it is usually not. To add a field in a LINQ query, it's more common to define a new anonymous type than to use ExpandoObject. That said, EO is fairly new, so this may become a more popular approach as time goes on.
Stephen Cleary
ok.. just wondering if I could find any excuse to use the new 4.0 stuff yet..
punkouter
+2  A: 

You don't state the context of your question, so I'll answer both LinqToObjects and LinqToSql.

In LinqToObjects, suppose you have a List<Customer> source.

  //Straight projection.
  //no new instances are created when query is evaluated.
IEnumerable<Customer> result =
  from c in source where c.Name == "Bob"
  select c;

  //Different Type projection
  //a new instance of CustomerName is created
  // for each element in the result when the query is evaluated.
IEnumerable<CustomerName> result =
  from c in source where c.Name == "Bob"
  select new CustomerName() {Name = c.Name};

  //Anonymous Type Projection    
  //a new instance of an anonymous type is created
  // for each element in the result when the query is evaluated.
  //You don't have access to the type's name
  // since the compiler names the type,
  // so you must use var to talk about the type of the result.
var result =
  from c in source where c.Name == "Bob"
  select new {Name = "Bob"};

  //Tuple Projection (same as Different Type Projection)
  //a new instance of Tuple is created
  // for each element in the result when the query is evaluated.
IEnumerable<Tuple<string, int>> result = 
  from c in source where c.Name == "Bob"
  select new Tuple<string, int>(){First = c.Name, Second = c.Id};

In LinqToSql, suppose you have an IQueryable<Customer> db.Customers

  //Straight projection
  //when the query is resolved
  // DataContext.Translate<Customer> is called
  // which converts the private dbReader into new Customer instances.
IQueryable<Customer> result =
  from c in db.Customers where c.Name == "Bob"
  select c;

  //Different Type Projection
  //when the query is resolved
  // DataContext.Translate<CustomerName> is called
  // which converts the private dbReader into new CustomerName instances.
  // 0 Customer instances are created.
IQueryable<Customer> result =
  from c in db.Customers where c.Name == "Bob"
  select new CustomerName() {Name = c.Name};

  //Different Type Projection with a twist
  //when the query is resolved
  // DataContext.Translate<CustomerGroup> is called
  // which converts the private dbReader into new CustomerGroup instances.
  // 0 Customer instances are created.
  //the anonymous type is used in the query translation
  // yet no instances of the anonymous type are created.
IQueryable<Customer> result =
  from c in db.Customers
  group c by new {c.Name, TheCount = c.Orders.Count()} into g
  select new CustomerGroup()
  {
    Name = g.Key.Name,
    OrderCount = g.Key.TheCount,
    NumberInGroup = g.Count()
  };

Ok, that's enough for now.

David B
I am using linq2entities so I think it is like your first example. Is there any reason or advantage to use tuple over anonymous ?
punkouter
Instances of anonymous types don't cross method boundaries very well. Tuples have no trouble with this.
David B
but in the basic case of sending back a object in a quick linq query without having to define a new class I guess thats the whole point of anon types.
punkouter
well - more than that - anon types let you create a structure that aids in the creation of the query, even if no instances are actually created. See last example. Imagine if you had to make a type for that.
David B