如何迭代Linq分组结果集?

6

我正在从我的数据库中获取一些数据,并使用linq计算总和、计数和分组数据。

        var si = _repository.GetAllByDate(date);

        var cs = from s in si
        group s by s.Name into g
        select new { Comm = g.Key, SIList = g.ToList(), Count = g.Count() };

我现在需要将cs传递给另一个类中的方法,以便可以提取组中每个项目的Comm、SIList和Count,我应该将其作为什么类型进行传递?IEnumerable不起作用。实际的linq group结果类型似乎是:

{System.Linq.Enumerable.WhereSelectEnumerableIterator<System.Linq.IGrouping<Model.Domain.MasterData.MyItem,Model.Domain.SI<>f__AnonymousTyped<Model.Domain.MasterData.MyItem,System.Collections.Generic.List<Model.Domain.SI>,int>>}

有什么想法吗?我希望能够将cs作为变量传递并在那里进行迭代。


尝试使用 vardynamic - Saeed Neamati
像这样吗?→ foreach(var x in cs) { foreach(var y in x.SIList) } ? - shenhengbin
基本上,匿名类使得保持强类型变得困难。按照Yuck的建议创建一个具体类型。 - captncraig
@scott,他想把它传递给另一个方法。那个foreach循环只能在这个直接作用域中起作用。 - captncraig
5个回答

7

如果您的匿名类型将在不同范围内使用,那么您需要创建一个与其定义相匹配的类型。

public class SomeClass {
    public Comm Comm { get; set; }
    public IList<String> SIList { get; set; }
    public Int32 Count { get; set; }
}

var si = _repository.GetAllByDate(date);

var cs = from s in si
         group s by s.Name into g
         select new SomeClass { Comm = g.Key, SIList = g.ToList(), Count = g.Count() };

编辑: 我们可以假设这个列表将是String类型的,所以我进行了相应的修改。如果这个类型不正确,你需要相应地更改IList<T>定义。


cs现在是一个IEnumerable <SomeClass>。 - captncraig
@CMP:没错,你可以创建一个方法,如 public void AnotherMethod(IEnumerable<SomeClass> someClassQueryResult) { } - Yuck
我通常使用结构体而不是类,因为你只需要对数据进行分组,而不需要使用“SomeClass”定义任何方法。 - Gage
2
@Gage:结构体用于实现值类型,实现起来更难且使用起来更棘手。在你有充分理由使用结构体之前,应该坚持使用类。 - Guffa

3
由于查询使用了惰性执行,因此您得到的类型非常复杂。您正在查看返回结果的表达式类型,而不是结果类型。
结果类型为 IEnumerable<_hidden_internal_class_name_>,也就是说,由于您在查询中创建了匿名对象,结果是编译器内部创建的类的对象流。
将该结果传递给另一个方法几乎没有用处,因为它需要使用反射来读取对象中的属性。您应该为结果中的对象创建一个命名类,以便轻松访问其属性。

1
      class Pet
        {
            public string Name { get; set; }
            public int Age { get; set; }
        }

        // Uses method-based query syntax.
        public static void GroupByEx1()
        {
            // Create a list of pets.
            List<Pet> pets =
                new List<Pet>{ new Pet { Name="Barley", Age=8 },
                               new Pet { Name="Boots", Age=4 },
                               new Pet { Name="Whiskers", Age=1 },
                               new Pet { Name="Daisy", Age=4 } };

            // Group the pets using Age as the key value 
            // and selecting only the pet's Name for each value.
            IEnumerable<IGrouping<int, string>> query =
                pets.GroupBy(pet => pet.Age, pet => pet.Name);

            // Iterate over each IGrouping in the collection.
            foreach (IGrouping<int, string> petGroup in query)
            {
                // Print the key value of the IGrouping.
                Console.WriteLine(petGroup.Key);
                // Iterate over each value in the 
                // IGrouping and print the value.
                foreach (string name in petGroup)
                    Console.WriteLine("  {0}", name);
            }
        }

        /*
         This code produces the following output:

         8
           Barley
         4
           Boots
           Daisy
         1
           Whiskers
        */

0
创建一个类型是一个很好的想法,但是为什么要这样做呢?当可以返回一个Tuple而不需要创建一个新的类或结构时。如果需要的是本地和/或内部的,并且该类不会被重用,请尝试使用Tuple。
Select new Tuple<Comm, IEnumerable<string>, Int32>( new Comm(), myStringList.AsEnumerable(), myCount )

-2

将其作为object传递,并在您的foreach循环中使用var作为迭代器。


将其作为对象传递需要在获取和使用枚举器之前进行转换。这并不是最好的选择。 - captncraig

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接