构造匿名类型和嵌套循环的通用列表

时间:2010-08-13 01:34:44

标签: c# generics list anonymous-types

我希望通过在嵌套循环中迭代两个其他列表来构造一个匿名类型列表。

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
            });
        }
    }
}

我知道我可以使用ToList()构建一个匿名类型列表,(参见this question),但我无法看到在上述情况下如何使用它。

请注意,我无法更改GetAllXGetAllY方法。

4 个答案:

答案 0 :(得分:4)

简单的答案是“你不应该”。

有一个 hacky 技巧,可让您这样做:

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

但按照预期的方式使用它真的更合理:

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

如果由于某种原因你真的不能使用这种纯函数样式,或者你发现你必须在多个地方实例化这样的列表,你应该声明一个普通的类而不是使用匿名类型。请记住,匿名类型无论如何都要编译成类,所以匿名类型没有性能优势,如果你不得不采用像这篇帖子顶部的hacky那样的技巧,那么甚至可读性/可维护性的好处也是值得怀疑的。

有些人建议使用List<dynamic>,但我建议不要这样做。它严重妨碍了可维护性,因为在编译时不再检查属性名称和类型(您可能会错误输入一个并获得运行时错误);它会降低运行时性能,因为每次访问都通过动态调度程序进行;而且,一旦你将对象放入这个列表中,你基本上就会被它们视为动态,因为你无法将它们强制转换为匿名类型。

答案 1 :(得分:1)

这段代码不是获得理想结果的最简单方法吗?

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

(Timwi - 我知道这是你的解决方案的“linqified”版本,但我想我会发布它,因为我觉得这种风格很容易阅读和遵循。)

答案 2 :(得分:0)

这里有两个选择。首先,您可以创建一个具有XY属性的简单类,并使列表成为该类对象的列表,如下所示:

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
            });
        }
    }
}

或者,您可以在C#4.0中使用它:

var myList = new List<dynamic>();

答案 3 :(得分:0)

由于您将X和Y放在同一个列表中,因此它们必须具有公共基类/接口。那么?他们之间没有关系?那么你为什么把它们放在同一个列表中呢!这不是一个好主意。

IEnumerable<BaseClass> AllXY = 
            GetAllX().Cast<BaseClass>().Union(GetAllY().Cast<BaseClass>());
foreach(var base in AllXY)
{
    //do something to base, usually with polymorphism
}