zoukankan      html  css  js  c++  java
  • IEnumeralbe<T>被误用一例

    我一直使用Linq To SQL,以前一直没有问题,但前两天发生了一件怪事。先写个示例代码有助于理解。

     1 /// <summary>根据指定的参数和分页信息搜索文章,并输出分页情况。</summary>
     2 /// <param name="title">文章标题包含的内容。</param>
     3 /// <param name="keyword">文章关键字包含的内容。</param>
     4 /// <param name="pageIndex">从0开始的页码。</param>
     5 /// <param name="pageSize">每页包含的记录数。</param>
     6 /// <param name="pageCount">输出总页数。</param>
     7 /// <param name="total">输出匹配记录的总数目。</param>
     8 /// <return>返回匹配文章的数组。</return>
     9 public static Article[] QueryArticles(string title, string keyword, int pageIndex, int pageSize, out int pageCount, out int total)
    10 {
    11     using (FormusDataContext dc = new ForumsDataContext())
    12     {
    13         Dictionary<stringobject> args = new Dictionary<stringobject>();
    14         args["Title"= title;
    15         args["Keyword"= keyword;
    16         var q = ParseQuery(args, dc.Articles);
    17 
    18         total = q.Count();
    19         pageCount = (int)Math.Ceiling((double)total / (double)pageSize);
    20 
    21         q = q.OrderByDescending(o => o.PostTime).Skip(pageIndex * pageSize).Take(pageSize);
    22         return q.ToArray();
    23     }
    24 }
    25 
    26 // 根据参数字典生成查询。
    27 private static IEnumerable<Article> ParseQuery(Dictionary<stringobject> args, IEnumerable<Article> source)
    28 {
    29     var q = source;
    30 
    31     if (args.ContainsKey("Title"))
    32     {
    33         string value = (string)args["Title"];
    34         q = q.Where(o => o.Title.Contains(value));
    35     }
    36 
    37     if (args.ContainsKey("Keyword"))
    38     {
    39         string value = (string)args["Keyword"];
    40         if (!string.IsNullOrEmpty(keyword))
    41         {
    42             q = q.Where(o => o.Keywords.Contains(value));
    43         }
    44     }
    45 
    46     // 解析其它参数
    47 
    48     return q;

    49 } 

    粗粗一看,这段程序并没有什么大问题,它的主要功能是提供了一个文章搜索的功能,通过指定文章的标题和关键字来检索数据。可在实际运行时,我发现如果提供了keyword这个参数时,程序就会在第18行抛出一个NullReferenceException,而错误是由Linq中的o.Keywords.Contains(value)引起的,因为Keywords这个字段在数据库里是可能有空值的。起始我很纳闷,q.Count()应该是由Linq To SQL生成一条SQL语句在数据库里执行,怎么会在C#的代码里出现这个错误呢。通过一番猜想和试验,我找到了问题的所在。 

    罪魁祸首就是ParseQuery这个方法的参数和返回值使用了IEnumerable泛型类,这样整个查询连接起来就是一个混合体:
    dc.Articles.Where(o => o.Keyword.Contains("...")).Count()
    接下来会发生什么呢?很明显,整条语句的前半部分dc.Articles会通过Linq To  SQL来执行,它会把数据库中表的所有内容都读出来,剩下的一部分会通过Linq To Object来执行,仅仅对已生成的对象统计一个数量。而因为Linq To Object是在C#代码中执行的,就会发生之前所说的问题了。而即使不出现这样的错误,这种情况也是不能容忍的,因为每次执行都会把所有的数据都读出来,那个效率可想而知了。

    要解决这个问题很简单,把ParseQuery方法的参数和返回值改成IQueryable<Article>就可以了。在此,也要提醒自己和广大的同行们,在使用扩展方法时应该注意,对于在有继承关系的类型上定义了相同名称和参数的扩展方法,必须准确的明白自己要调用的是哪个类型的扩展方法,而在调用时应该显式地将变量声明为相应的类型,而不应该随意地声明为某个父类型。

    PS:以上代码是随手敲的,不保证代码可以通过编译。

  • 相关阅读:
    每天一点正能量
    嵌入式开发-写在这里作为参照
    产品设计与开发 之 开发流程和组织架构
    产品设计与开发 之 开头语
    机器视觉基础
    项目与运营
    3.Linux如何管理分区
    2.Linux系统之硬盘与分区基础知识
    1.Linux入门介绍
    shell笔记
  • 原文地址:https://www.cnblogs.com/effun/p/1993408.html
Copyright © 2011-2022 走看看