views:

1585

answers:

5

I am looking for best practices for creating collections made from anonymous types.

There are several approaches - this one and most answers on this thread assume that the whole anonymous collection can be constructed in one statement.

As anonymous types are usually used to replace classes that are to be used to store temporary (as put forward in this SO answer), I would like to avoid creating and using a class for anonymous collections, as this post suggests.

In my case, I am iterating over a collection - for each item in the collection I would like to collect related objects in an anonymous type (acting as a tuple). I need these anonymous types to be put in a collection and then sort them for further work.

Other approaches I have considered:

  1. Use an object[] or ArrayList (losing the benefit of the anonymous type)
  2. Creating a wrapper class for the required items (removing the need for the anonymous type)

This is the only place in my code that I need such a collection - what would be the best approach?

Additional Information:

I am working with legacy .Net 1.1 objects, so the collections I am working with are strongly typed collections implementing IEnumerable, and as such most Linq extension methods such as .Select won't work:

Code sample

foreach (Item item in myItems)
{
 foreach (Confirmation confirmation in item.GetConfirmations(true))
 {
  if (lastParentId != item.ParentId)
  {
   lastParentId = item.ParentId;
   parentObject = new ParentItem(lastParentId);
  }

  itemHolder = new ArrayList { item, confirmation };
  if (parentObject!= null)
  {
      itemHolder.Add(parentObject.Rate);
  }

     sortConfirmations.Add(confirmation.Date, itemHolder);
    }
}

// Use sortConfirmations

Resolution

I ended up using a generic dictionary to collect the related items together and using .OrderBy() to sort them - ugly, but it works... and is better than the existing code.

+3  A: 

One option is to use an example item to create the collection via generic type inference, for example:

    static List<T> CreateEmptyList<T>(T template) {
        return new List<T>();
    }
    void Foo() {
        var list = CreateEmptyList(new { Foo = "abc" });
        list.Add(new { Foo = "def" });
        //...
    }

You can also do this without creating an instance (but using an anonymous method that never gets caller), but I don't think it saves anything really... we might not create an instance of the object, but we do create an instance of a delegate, so not much of a saving...

You also mention sorting the data; see the reply here for a way to use List<T>.Sort with a lambda, and hence with anonymous types - i.e.

list.Sort(x=>x.Foo);
Marc Gravell
+2  A: 

If you're happy with an array, you can use an array initializer:

var items = new[] {
    new { Foo = "def" },
    new { Foo = "ghi" },
    new { Foo = "jkl" }
};

You can then call ToList() if you want to get a List<T> out. Marc's solution will be slightly more efficient than calling ToList() due to not needing the extra copying, but I think I'd probably use the "array and then ToList()" solution in most cases as there's less clutter. Of course, if performance is crucial for that bit of code, it changes things.

EDIT: As you're iterating over a collection, just use Select:

var anonymousItems = items.Select (item => new { Foo=item.Foo, 
                                                 Bar=item.Other })
                          .ToList();
Jon Skeet
Can't do that, as I am iterating over an existing collection to retrieve the objects I want to put into the anonymouse type. I was meaning to do collection.Add(anonType).
Oded
+1  A: 

For a very different answer... LINQ?

In my case, I am iterating over a collection - for each item in the collection I would like to collect related objects in an anonymous type (acting as a tuple). I need these anonymous types to be put in a collection and then sort them for further work.

That sounds like:

var list = (from item in collection
          from related in item.Relationship
          order by ...something...
          select new {item,related}).ToList()
Marc Gravell
Unfortunately I need to new up some of the objects I will be collecting in the anonymous type. I am converting some existing code that is putting these objects in an ArrayList and each array list into a SorteList. I need to achieve something similar, but cleaner.
Oded
@Oded - that is often still possible. Of course, it is hard to say for sure without a concrete example...
Marc Gravell
+1 for the "we need more information" point. I strongly suspect that LINQ is the way forward here.
Jon Skeet
+1  A: 

LINQ is the way to go. Assuming you want to fetch the related objects A, B and C of every item in a collection items and sort by the related object A you would go as follows.

var relatedObjects = items.
       Select(item => new { A = item.A, B = item.B, C = item.C } ).
       OrderBy(item => item.A);

You get a collection of items of an anonymous type with the three properties A, B and C set to the related objects ordered by the related object A.

I did not verify that, but you should be able to extend the relatedObject collection later. Just do the following to add a single new item. This should work because there is only one anonymous type per assembly I think if the names and types of each property match.

relatedObjects = relatedObjects.Union(
   Enumerable.Repeat(new { A = someA, B = someB, C = someC }, 1))

Quite ugly because of the Enumerable.Repeat() but becomes quite nice if you union with a collection of new items instead of a single new item.

Daniel Brückner
A: 

this one and most answers on this thread assume that the whole anonymous collection can be constructed in one statement.

Yes, you normally create a collection of anonymous type in a single statement. If you need more statements, you may end up with a pretty useless collection of different anonymous types.

Anonymous types are useful when you create them in a single statement, and use them right away. If the creation of the collection or the further processing is a bit more complex, the anonymous type loses some of it's usefulness. For example, you can't efficiently pass an anonymous type along to a method for processing, as the method doesn't know the type of the object and thus have to use reflection to get anything out of it.

If you are going to repeatedly look for items in this collection of anonymous types, you may want to create a named type so that you can put them in a Dictionary for much faster lookup.

Guffa
A *typed* collection, even of anonymous types, won't suffer the "collection of different anonymous types" fate; you can't put a "new {Foo="acb"}" in a collection of "new {Bar [int]}"
Marc Gravell
@Marc Gravell: Yes, of course, you would need something like a List<object> to handle both types, losing the direct connection to the anonymous type information.
Guffa