views:

54

answers:

4

I wish to construct a list of anonymous types constructed by iterating through two other lists in a nested loop.

var myList = new List<???>();
foreach (object x in GetAllX())
{
    if (Process(x))
    {
        foreach (object y in GetAllY(x))
        {
            myList.Add(new {
                X = x,
                Y = y
            });
        }
    }
}

I know that I can construct a List of anonymous types using ToList(), (see this question), but I can't see how I can use this in the above case.

Note that I can't change the GetAllX and GetAllY methods.

+1  A: 

The simple answer is “you shouldn’t”.

There is a hacky trick which allows you to do it:

var myList = new[] { new { X = (object) null, Y = (object) null } }.ToList();
myList.Clear();
foreach (object x in GetAllX())
    // ...

But it would really be more reasonable to use it the way it was intended:

var myList = GetAllX().Where(x => Process(x))
    .SelectMany(x => GetAllY(x).Select(y => new { X = x, Y = y }))
    .ToList();

If you really can’t use this pure-functional style for some reason, or you find you have to instantiate such a list in multiple places, you should probably declare a normal class instead of using an anonymous type. Remember that anonymous types are compiled into classes anyway, so there is no performance benefit to anonymous types, and even the readability/maintainability benefit is questionable if you have to resort to tricks like the hacky one at the top of this post.

Some people suggest to use List<dynamic>, but I recommend against it. It severely hampers maintainability because the property names and types are no longer checked at compile-time (you could mistype one and get a run-time bug); it slows down run-time performance because every access goes through the dynamic dispatcher; and also, once you put your objects into this list, you are basically stuck with them being dynamic, because you can’t cast them back to the anonymous type.

Timwi
A: 

You have two choices here. First, you could create a simple class that has X and Y properties and make your list a list of objects of that class, like so:

class NewClass
{
    public object X;
    public object Y;
}

var myList = new List<NewClass>();
foreach (object x in GetAllX())
{
    if (Process(x))
    {
        foreach (object y in GetAllY(x))
        {
            myList.Add(new NewClass() {
                X = x,
                Y = y
            });
        }
    }
}

Or, you could just use this in C# 4.0:

var myList = new List<dynamic>();
You get stronger type checking with the first option.
A: 

Since you put X and Y in the same list, they must have a common base class/interface.What? No relations between them? Then why do you put them in the same list! That's not a good idea.

IEnumerable<BaseClass> AllXY = 
            GetAllX().Cast<BaseClass>().Union(GetAllY().Cast<BaseClass>());
foreach(var base in AllXY)
{
    //do something to base, usually with polymorphism
}
Danny Chen
Why? X = categories, Y = things in that category, or perhaps X = directories, Y = files in that directory. There are loads of reason why you might want to do this in situations where it is a good idea to still keep X and Y separate in the resulting list.
Kragen
X=direcotires, Y=files, putting them in one list is meaningless.
Danny Chen
I think you have miss-read what it is I'm doing.
Kragen
+1  A: 

Wouldn't this code be the simplest way to achieve your desired result?

var myList = (from x in GetAllX()
              where Process(x)
              from y in GetAllY(x)
              select new
              {
                  X = x,
                  Y = y,
              }).ToList();

(Timwi - I know this is the "linqified" version of your solution, but I thought I would post it as I feel that in this style it is easy to read and follow.)

Enigmativity