当想对集合筛选的时候,经常想到用Where过滤,而实际上List<T>.FindAll()也是不错的选择。

如果有一个订单,属性有下单时间、区域等等。如何使用List<T>.FindAll(),根据年份、月份、天、区域来过滤呢?

□ 思路

List<T>.FindAll(Predicate<T> match)方法
Predicate<T>是一个泛型委托,返回bool类型:
public delegate bool Predicate<T>(T obj)
也就是说,match参数是一个返回bool类型的方法,由此,我们可以定义一个泛型类,并在其中自定义返回bool类型的方法,即筛选规则,最后把该方法交给委托。

最终视图界面输入年份、月份、天与订单类中的下单时间属性进行比较。首先想到把年份、月份、天封装到一个类中与订单类进行比较。考虑到有可能存在其它类也有时间属性,都有可能进行有关时间的筛选。这样,可以把时间属性抽象成接口,凡是实现该接口的,都可以与封装年份、月份、天的类进行比较。

using System;
 
namespace ObjectFilter.Interface
{
    public interface IDate
    {
        DateTime Date { get; set; } 
    }
}

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

让Order类实现IDate接口。

using System;
using ObjectFilter.Interface;
 
namespace ObjectFilter.Models
{
    public class Order : IDate
    {
        public int ID { get; set; }
        public DateTime Date { get; set; } //接口属性
        public string Area { get; set; }
    }
}
 

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

封装年份、月份、天的类需要面向IDate接口,并提供一个返回bool类型的比较方法。

    public class DateFilter<T> where T:IDate
    {
        private int year;
        private int month;
        private int day;
 
        public DateFilter(int year, int month, int day)
        {
            this.year = year;
            this.month = month;
            this.day = day;
        }
 
        public DateFilter(DateTime date) : this(date.Year, date.Month, date.Day){}
        public DateFilter(int year, int month) : this(year, month, 0){}
        public DateFilter(int year) : this(year, 0, 0){}
        public DateFilter() : this(0, 0, 0){}
 
        //自定义规则:只要有T的Date属性值与本类的字段有一个不等,就返回false
        public virtual bool MatchRule(T item)
        {
            if(year != 0 && year !=item.Date.Year)
                return false;
            if(month != 0 && month != item.Date.Month)
                return false;
            if(day !=0 && day != item.Date.Day)
                return false;
            return true;
        }
    }

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

如何针对Order中的Area属性筛选呢?可以设计一个DateFilter<Order>的继承类,使子类不但有父类的筛选逻辑,并在此基础上增加一个对Area属性的筛选。

   1:      public class OrderFilter : DateFilter<Order>
   2:      {
   3:          private string area;
   4:   
   5:          public OrderFilter(int year, int month, int day, string area)
   6:              : base(year, month, day)
   7:          {
   8:              this.area = area;
   9:          }
  10:   
  11:          public override bool MatchRule(Order item)
  12:          {
  13:              bool result = base.MatchRule(item);
  14:              if (result == false)
  15:                  return false;
  16:              if (string.IsNullOrEmpty(area) || String.Compare(item.Area, area, true) == 0)
  17:              {
  18:                  return true;
  19:              }
  20:              else
  21:              {
  22:                  return false;
  23:              }
  24:          }
  25:      }
  26:   

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

模拟一个服务层,一个方法用来获取所有订单信息,另一个方法根据条件筛选出订单集合,只需要把自定义泛型类DateFilter<Order>的MatchRule交给Predicate<T>泛型委托就行。

using System;
using System.Collections.Generic;
using ObjectFilter.Helper;
using ObjectFilter.Models;
 
namespace ObjectFilter
{
    public static class Service
    {
        public static List<Order> GetOrders()
        {
            return new List<Order>()
            {
                new Order(){ID = 1,Area = "青岛",Date = new DateTime(2013,8,1)},
                new Order(){ID = 2,Area = "平度",Date = new DateTime(2013,9,1)},
                new Order(){ID = 3,Area = "即墨",Date = new DateTime(2013,9,3)},
                new Order(){ID = 4,Area = "香港",Date = new DateTime(2013,9,3)},
                new Order(){ID = 5,Area = "北京",Date = new DateTime(2014,1,2)},
                new Order(){ID = 6,Area = "上海",Date = new DateTime(2014,1,2)},
            };
        }
 
        public static List<Order> GetOrdersBy(DateFilter<Order> filter)
        {
            return GetOrders().FindAll(new Predicate<Order>(filter.MatchRule));
        }
    }
}
 

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

控制器有2个方法,一个方法返回所有的订单,另一个方法接收来自前台的筛选参数,根据这些参数生成自定义泛型类DateFilter<Order>实例作为服务层方法参数,最终返回部分视图。

using ObjectFilter.Helper;
using ObjectFilter.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
 
namespace ObjectFilter.Controllers
{
    public class HomeController : Controller
    {
 
        public ActionResult Index()
        {
            List<SelectListItem> years = new List<SelectListItem>();
            years.Add(new SelectListItem(){Text = "2013",Value = "2013"});
            years.Add(new SelectListItem() { Text = "2014", Value = "2014" });
            ViewData["y"] = years;
 
            List<SelectListItem> months = new List<SelectListItem>();
            for (int i = 1; i <= 12; i++)
            {
                months.Add(new SelectListItem(){Text =i.ToString(),Value = i.ToString()});
            }
            ViewData["m"] = months;
 
            List<SelectListItem> days = new List<SelectListItem>();
            for (int i = 1; i <= 31; i++)
            {
                days.Add(new SelectListItem(){Text = i.ToString(),Value = i.ToString()});
            }
            ViewData["d"] = days;
 
            return View(Service.GetOrders());
        }
 
        [HttpPost]
        public ActionResult GetOrdersBy(string y, string m, string d, string area)
        {
            DateFilter<Order> filter = new OrderFilter(Convert.ToInt32(y), Convert.ToInt32(m), Convert.ToInt32(d), area);
            return View(Service.GetOrdersBy(filter));
        }
 
    }
}
 

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

呈现所有订单的视图界面中,当点击"筛选"按钮,把筛选条件通过ajax传递给控制器方法,返回的部分视图最终呈现到本页的一个div中。

展开@model IEnumerable<ObjectFilter.Models.Order>

@{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
} @Html.DropDownList("year",(IEnumerable<SelectListItem>)ViewData["y"],"选择年份",new {id="year"}) <br/>
@Html.DropDownList("month",(IEnumerable<SelectListItem>)ViewData["m"],"选择月份",new {id="month"}) <br/>
@Html.DropDownList("day",(IEnumerable<SelectListItem>)ViewData["d"],"选择天数",new {id="day"}) <br/>
<input type="text" id="area"/> <br/>
<input type="button" id="btn" value="筛选"/>
<div id="content">
<table>
<tr>
<th>
@Html.DisplayNameFor(model => model.Date)
</th>
<th>
@Html.DisplayNameFor(model => model.Area)
</th>
<th></th>
</tr> @foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.Date)
</td>
<td>
@Html.DisplayFor(modelItem => item.Area)
</td>
<td>
</td>
</tr>
} </table>
</div>
<hr/>
<h3>以下为筛选结果:</h3>
<div id="filter"></div> @section scripts
{
<script type="text/javascript">
$(function() {
$('#btn').on('click', function() {
$.ajax({
cache: false,
url: '@Url.Action("GetOrdersBy", "Home")',
type: "POST",
data: { y: $('#year').val(), m: $('#month').val(), d: $('#day').val(), area: $('#area').val() },
success: function (data) {
$('#filter').html(data);
},
error: function (jqXhr, textStatus, errorThrown) {
alert("出错了 '" + jqXhr.status + "' (状态: '" + textStatus + "', 错误为: '" + errorThrown + "')");
}
});
});
});
</script>
} 点击"筛选"按钮返回部分视图为: @model IEnumerable<ObjectFilter.Models.Order> <table>
<tr>
<th>
@Html.DisplayNameFor(model => model.Date)
</th>
<th>
@Html.DisplayNameFor(model => model.Area)
</th>
<th></th>
</tr> @foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.Date)
</td>
<td>
@Html.DisplayFor(modelItem => item.Area)
</td>
<td>
</td>
</tr>
}
</table>

结果:

输入时间筛选:

 

输入时间和区域筛选:

 

□ 总结

先把目标对象中需要筛选的属性抽象成接口属性,然后设计一个能接收筛选条件的泛型类,并提供一个返回bool类型的方法,该方法把接收到的来自客户端的筛选条件与目标对象的属性进行比较。最后,只需要把自定义泛型类返回bool类型的方法交给Predicate<T>这个泛型委托即可:FindAll(new Predicate<Order>(filter.MatchRule))。

MVC对集合筛选,不使用Where(),而使用FindAll()的更多相关文章

  1. 关于Linq对DataTable和List各自的两个集合筛选的相关操作技巧

    项目中用到了对两个集合的帅选等操作,简单总结下 1.Linq操作多个Datable 可以通过AsEnumerable()方法对DataTable进行Linq操作 //获取数据表所有数据 DataTab ...

  2. Spring mvc接受集合类型参数的方法

    public String xxxxx(String xxxx, String xxxxx, @RequestParam("parameterList[]") List<St ...

  3. FreeMarker与Spring MVC 4集合的HelloWorld示例

    0.整体的项目结构 1.引入POM <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="ht ...

  4. CollectionUtils.select 集合筛选

    import org.apache.commons.collections.CollectionUtils;import org.apache.commons.collections.Predicat ...

  5. python3编程技巧二——如何在列表、字典、集合 中根据条件筛选数据

    一.列表筛选数据 # coding=utf-8 from random import randint # 创建随机列表 l = [randint(-10, 10) for i in range(10) ...

  6. 【半小时大话.net依赖注入】(下)详解AutoFac+实战Mvc、Api以及.NET Core的依赖注入

    系列目录 上|理论基础+实战控制台程序实现AutoFac注入 下|详解AutoFac+实战Mvc.Api以及.NET Core的依赖注入 前言 本来计划是五篇文章的,每章发个半小时随便翻翻就能懂,但是 ...

  7. C#学习总结之集合

    一.集合接口和类型 命名空间:  集合类型  命名空间  一般集合 System.Collections   泛型集合 System.Collections.Generic   特定类型集合 Syst ...

  8. MVC 使用HandleErrorAttribute统一处理异常

    HandleErrorAttribute继承自FilterAttribute,且实现了IExceptionFilter接口. 属于AOP思想的一种实现,MVC的四大筛选器(权限,动作,结果,异常)中的 ...

  9. asp.net core 2.2 中的过滤器/筛选器(上)

    ASP.NET Core中的过滤器/筛选器 通过使用 ASP.NET Core MVC 中的筛选器,可在请求处理管道中的特定阶段之前或之后运行代码. 注意:本主题不适用于 Razor 页面. ASP. ...

随机推荐

  1. 10 个优质的 Laravel 扩展推荐

    这里有 10+ 个用来搭建 Laravel 应用的包 为何会创建这个包的列表?因为我是一个「比较懒」的开发者,在脸书上是多个 Laravel 小组的成员.平日遇到最多的问题就是开发是需要用那些包.我很 ...

  2. elasticsearch学习笔记--原理介绍

    前言:上一篇中我们对ES有了一个比较大概的概念,知道它是什么,干什么用的,今天给大家主要讲一下他的工作原理 介绍:ElasticSearch是一个基于Lucene的搜索服务器.它提供了一个分布式多用户 ...

  3. 什么是 CLR(转)

    CLR(公用语言运行时)和Java虚拟机一样也是一个运行时环境,它负责资源管理(内存分配和垃圾收集),并保证应用和底层操作系统之间必要的分离..NET提供了一个运行时环境,叫做公用语言运行时(Comm ...

  4. sicily 1051. Biker's Trip Odomete

    DescriptionMost bicycle speedometers work by using a Hall Effect sensor fastened to the front fork o ...

  5. java内存溢出分析工具

    http://www.cnblogs.com/preftest/archive/2011/12/08/2281322.html java内存溢出分析工具:jmap使用实战 在一次解决系统tomcat老 ...

  6. css如何画出类似原生的线条?

    做前端的程序猿特别是移动端的,都很头疼遇到一种情况就是需要div底部加一个线条但是 1px的效果很粗,跟设计案上的不符合. 我的一个伙伴查找出来的一个解决方法: 在需要加上的线条的地方加上一个div ...

  7. bzoj 1228 [SDOI2009]E&D

    sg表很好打,规律很不好找.... #include<bits/stdc++.h> #define LL long long #define fi first #define se sec ...

  8. ifdown eth0或service network restart

    错误提示信息如下: Shutting down interface eth0:  Error: Device 'eth0' (/org/freedesktop/NetworkManager/Devic ...

  9. <泛> 归并排序 及 逆序对

    今天写一个归并排序的模板,返回值为该序列的逆序对数 基本思路 归并排序就是利用二分的思想,将区间无限递归二分,直到当前划分区间只包含一个元素或没有元素的时候(我们认为这个序列是自动有序的),我们回溯到 ...

  10. java面试数据类型

    1. Java的数据类型? 2. Java的封装类型? 3. 基本类型和封装类型的区别? 基本类型只能按值传递,而对应的封装类是按引用传递的. 基本类型是在堆栈上创建的,而所有的对象类型都是在堆上创建 ...