代码之家  ›  专栏  ›  技术社区  ›  Justin

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

  •  1
  • Justin  · 技术社区  · 15 年前

    我希望构造一个匿名类型列表,该列表是通过在嵌套循环中遍历另外两个列表构造的。

    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

    请注意,我无法更改 GetAllX GetAllY 方法。

    4 回复  |  直到 9 年前
        1
  •  5
  •   Timwi    15 年前

    简单的答案是你不应该。

    有一个 黑的 让你做到这一点的技巧:

    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> ,但我反对。它严重阻碍了可维护性,因为在编译时不再检查属性名和类型(您可能会错误地键入一个属性名和类型,从而导致运行时错误);它会降低运行时性能,因为每次访问都通过动态调度器;而且,一旦你把你的对象放到这个列表中,你基本上就被困在它们是动态的,因为你不能把它们转换回匿名类型。

        2
  •  1
  •   Enigmativity    15 年前

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

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

        3
  •  0
  •   Jeff Mattfield Jeff Mattfield    15 年前

    X Y

    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>();
    
        4
  •  0
  •   Cheng Chen    15 年前

    既然你把X和Y放在同一个列表中,它们必须有一个共同的基类/接口。什么?他们之间没有关系?那你为什么要把他们放在同一张单子上!这不是个好主意。

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