среда, 6 июля 2011 г.

How to create a generic List of anonymous types?

There was a question on one of the forums asking how to create a list of anonymous types given a single instance of an anonymous type:
var Customer = new { FirstName = "John", LastName = "Doe" };
            var customerList = new List<????>();

My first reaction was to answer that this was impossible, and even if it was, for what purpose, but thankfully people replied before me, who knew better. I was amazed by these ingenious tricks. For example, Kael Rowan suggested:

var Customer = new { FirstName = "John", LastName = "Doe" };
            var customerList = (new[] { Customer }).ToList();
            
            customerList.Add(new { FirstName = "Bill", LastName = "Smith" });

I think this is brilliant! This technique is called casting by example. Here's another implementation, using a "list factory":

static void Main(string[] args)
        {
            var Customer = new { FirstName = "John", LastName = "Doe" };
            var customerList = MakeList(Customer);
            
            customerList.Add(new { FirstName = "Bill", LastName = "Smith" });
        }

        public static List MakeList(T itemOftype)
        {
            List newList = new List();
            return newList;
        }        

They use generic type inference here to "name" the anonymous type to T and return a List of it.

This somewhat made me think of var as a black hole - once a type is being "converted" to a var, it can never come back explicitly (well, unless you want to cast :) It can reappear in another method as another "var" (casting by example) or be remanifested as inferred generic type parameter, but it can't get an explicit name ever again.

There was a discussion a while ago (between Wilco BauwerRick Strahl and yours truly), whether C# should extend type inference to return types of methods, types of fields, properties etc. : Returning var from a method in C# 3.0 Generally it was agreed that this would not be a good thing to do, for various reasons. Eric Lippert gave a good summary of all the trouble it might bring:

  • what if languages consume the method, which don't support type inference?
  • how to store this in CLR metadata?
  • how to detect versioning problems once you update your class?
  • how to deal with two structurally identical types from different assemblies?
  • etc.

My personal feeling about this all (which sort of corresponds with the general consensus), is that one shouldn't use anonymous types for more than trivial LINQ operations. If a type is going to be reused, give it a proper name and declaration. Anonymous types don't scale (at least, not in C# 3.0).

If there is ever going to be a C# feature to use var as a return type of members, this is going to be the first time ever I'll want the C# team not to implement a feature :)

Комментариев нет: