当想对集合筛选的时候,经常想到用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. Java 中 日期 时间 加减

    DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); //方法1(推荐,功能强大灵活多变) Ca ...

  2. MySQL 5.1完全卸载

    第一步:控制面板里的增加删除程序内进行删除 第二步:删除MySQL文件夹下的my.ini文件,如果备份好,可以直接将文件夹全部删除 第三步:regedit进入注册表 HKEY_LOCAL_MACHIN ...

  3. 2015309南皓芯实验二 Java面向对象程序设计

    一.实验内容 初步掌握单元测试和TDD 理解并掌握面向对象三要素:封装.继承.多态 初步掌握UML建模 熟悉S.O.L.I.D原则 了解设计模式 实验要求 1.没有Linux基础的同学建议先学习< ...

  4. Android studio代码实现打电话+点击事件四种方式

    Android系统架构(重点) 第一层:应用层Application 第二层:应用框架层Application Framework 第三层:Android底层类库层 Libraries.Dalvik虚 ...

  5. 【Java】 Scanner类的几个方法

    通过 Scanner 类可以获取用户的输入,创建 Scanner 对象的基本语法如下: Scanner sc = new Scanner(System.in); nextInt().next()和ne ...

  6. linux/mac下命令行rm回收站--rmtrash

    Linux.mac的命令行下没有回收站功能,很多时候手一抖就把重要文件给 rm -fr * 了,虽然linux下有可能通过lost +found/debugfs找回,但难度也比较大,不能保证一定能够找 ...

  7. CSUOJ 2031 Barareh on Fire

    Description The Barareh village is on fire due to the attack of the virtual enemy. Several places ar ...

  8. UNP学习总结(二)

    本文是UNP复习系列的第二篇,主要包括了以下几个内容 UNIX系统下5种I/O模型 阻塞.非阻塞,同步.异步 epoll函数用例 一.Unix下的五种可用I/O模型 阻塞式I/O模型 阻塞式I/O是最 ...

  9. 机器学习之路: python 支持向量机 LinearSVC 手写字体识别

    使用python3 学习sklearn中支持向量机api的使用 可以来到我的git下载源代码:https://github.com/linyi0604/MachineLearning # 导入手写字体 ...

  10. tomcat启动startup.bat一闪而过的问题处理方式

    tomcat在启动时,会读取环境变量的信息,需要一个CATALINA_HOME 与JAVA_HOME的信息,CATALINA_HOME即tomcat的主目录,JAVA_HOME即Java安装的主目录, ...