none
Linq严重bug: where 中比较Type语句无效!! RRS feed

  • 问题

  •  

        class AA{}
        class BB: AA{} 
        class CC: AA{}
    
        [TestMethod]
        public void TestLinqType()
        {
          //制造测试数据
          Dictionary<int, AA> dict = new Dictionary<int, AA>();
          dict.Add(1, new BB());
          dict.Add(2, new BB());
          dict.Add(3, new CC());
          dict.Add(4, new CC());
    
          //使用foreach进行筛选,完全没有问题
          IEnumerable<BB> rst1 = GetItems_Foreach<BB>(dict);
          int n1 = rst1.Count();
          foreach (BB crrItem in rst1) ;
    
          //使用Linq进行筛选,运行不出错。但结果遍历结果异常
          IEnumerable<BB> rst2 = GetItems_LinqType<BB>(dict);
          int n2 = rst2.Count(); //异常:不能把CC转化为BB, 说明结果中有CC
          foreach (BB crrItem in rst2) ;//异常:不能把CC转化为BB, 说明结果中有CC
    
        }
    
        /// 用Linq在集合dict中筛选所有类型是T的元素
        IEnumerable<T> GetItems_LinqType<T>(Dictionary<int, AA> dict) where T:AA
        {
          return from T crrItem
              in dict.Values
              where crrItem.GetType() == typeof(T)
              select crrItem;
        }
    
        /// 用Linq在集合dict中筛选所有类型是T的元素
        IEnumerable<T> GetItems_Foreach<T>(Dictionary<int, AA> dict) where T : AA
        {
          List<T> rst = new List<T>();
          foreach (AA crrItem in dict.Values)
          {
            if (crrItem.GetType() == typeof(T))
              rst.Add(crrItem as T );
          }
          return rst;
        }
    
    
    2011年2月17日 3:26

答案

  • 您好,在GetItems_Foreach<T>方法中,您指明了类型都转为AA,在这句foreach (AA crrItem in dict.Values),而linq确是要求转为BB,CC跟BB之间没有任何关系,当然错!


    执行Linq语句本身并没有出错,而且返回了结果集.  但是在遍历结果集的时候出了错.

    按理说条用的时候已经指明了T=BB ,因此结果集中应该尽包含BB对象才对. 但是在遍历中发现了CC对象,所以才会出错的.

    问题是, Linq结果集不符合预期.


    最近信了奎爷!

    1、Linq语句的真正执行,不是在Linq那句话,而是在Linq之后,真正要使用集合时才执行。您可以将

    from T crrItem
    in dict.Values
    where crrItem.GetType() == typeof(T)
    select crrItem

    理解为一个sql语句,此时并未查结果,而是在下面的

    int
     n2 = rst2.Count();

    或foreach时才查询结果。

    2、在linq的方法里传递的是dict,这个是包含BB和CC的集合。在这个集合里面查找自然会出错。你写的linq相当于

    foreach (BB crrItem in dict.Values)
    
    
    {
    
    
     if (crrItem.GetType() == typeof(T))
    
    
     rst.Add(crrItem as T );
    
    
    }
    
    
    

    2011年2月17日 8:48
    版主
  • 感谢JiYuan 的详细解释!!

    原来Linq语句的真正执行,不是在Linq那句话,而是在Linq之后,真正要使用集合时才执行。

    而且我的Linq相当于写成了foreach (BB crrItem in dict.Values), 所以才出了错。


    最近信了奎爷!
    2011年2月17日 10:23

全部回复

  • 您好,在GetItems_Foreach<T>方法中,您指明了类型都转为AA,在这句foreach (AA crrItem in dict.Values),而linq确是要求转为BB,CC跟BB之间没有任何关系,当然错!
    2011年2月17日 3:57
    版主
  • 您好,在GetItems_Foreach<T>方法中,您指明了类型都转为AA,在这句foreach (AA crrItem in dict.Values),而linq确是要求转为BB,CC跟BB之间没有任何关系,当然错!


    执行Linq语句本身并没有出错,而且返回了结果集.  但是在遍历结果集的时候出了错.

    按理说条用的时候已经指明了T=BB ,因此结果集中应该尽包含BB对象才对. 但是在遍历中发现了CC对象,所以才会出错的.

    问题是, Linq结果集不符合预期.


    最近信了奎爷!
    2011年2月17日 8:18
  • 您好,在GetItems_Foreach<T>方法中,您指明了类型都转为AA,在这句foreach (AA crrItem in dict.Values),而linq确是要求转为BB,CC跟BB之间没有任何关系,当然错!


    执行Linq语句本身并没有出错,而且返回了结果集.  但是在遍历结果集的时候出了错.

    按理说条用的时候已经指明了T=BB ,因此结果集中应该尽包含BB对象才对. 但是在遍历中发现了CC对象,所以才会出错的.

    问题是, Linq结果集不符合预期.


    最近信了奎爷!

    1、Linq语句的真正执行,不是在Linq那句话,而是在Linq之后,真正要使用集合时才执行。您可以将

    from T crrItem
    in dict.Values
    where crrItem.GetType() == typeof(T)
    select crrItem

    理解为一个sql语句,此时并未查结果,而是在下面的

    int
     n2 = rst2.Count();

    或foreach时才查询结果。

    2、在linq的方法里传递的是dict,这个是包含BB和CC的集合。在这个集合里面查找自然会出错。你写的linq相当于

    foreach (BB crrItem in dict.Values)
    
    
    {
    
    
     if (crrItem.GetType() == typeof(T))
    
    
     rst.Add(crrItem as T );
    
    
    }
    
    
    

    2011年2月17日 8:48
    版主
  • 感谢JiYuan 的详细解释!!

    原来Linq语句的真正执行,不是在Linq那句话,而是在Linq之后,真正要使用集合时才执行。

    而且我的Linq相当于写成了foreach (BB crrItem in dict.Values), 所以才出了错。


    最近信了奎爷!
    2011年2月17日 10:23