上面的方法虽然可以完成任务,但是不够好,为什么呢?
实际上,这些问题.Net Framework已经为我们想到了,并在List<T>上提供了一个FindAll(Predicate<T> match)方法来进行筛选的工作,而Predicate<T>类型的参数,封装了筛选的规则。Predicate<T>是一个泛型委托,这意味着match参数是一个返回bool类型的方法,在FindAll()内部,会调用我们传递进去的这个方法。
public delegate bool Predicate<T>(T obj);
NOTE:我看到过这样的一句话,是问Librariy和Framework的区别是什么?回答是:我们调用Librariy的方法,但是Framework调用我们的方法(当然我们也会调用Framework)。可见Framework是一个扩展性和弹性很高的东西,在很多地方我们可以将自己的代码融入到Framework中去。
现在我们来看下如何定义满足 Predicate<T>委托的方法。如果我们将方法写在OrderManager类的内部,那么似乎可以这样写:
// 进行数据筛选的主要逻辑
public bool MatchRule(Order 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;
}
可实际上,你发现没有地方来传递year, month, day参数,因为Predicate<T>(T obj)要求只接受一个参数,在这里是Order类型的item。所以,实际上我们要对这个方法进行一个简单的封装,让我们可以传递year, month, day参数进去。在进行封装之前,我们应该考虑:对于年、月、日的筛选是很常见的操作,我们要让代码重用。
我们先定义一个接口,这个接口仅要求返回一个DateTime类型的属性Date,对于所有实现了这个接口的类,都应该可以使用我们的筛选方法(一个没有日期的对象显然不能按年、月、日筛选)。
public interface IDate
{
DateTime Date { get; }
}
此时我们的Order类也应该进行修改,让它来实现这个接口,我们只需要它返回orderDate字段就可以了:
public class Order :IDate
{
// 略
public DateTime Date
{
get { return orderDate; }
}
}
接下来定义可以用于筛选的类,创建一个DateFilter.cs文件:
// 用于按照年、月、日筛选列表的泛型类,基类
public class DateFilter<T> where T : IDate
{
private int year;
private int month;
private int day;
public DateFilter(int year, int month, int day)
{
&