假设我有一个名为GetCatsByColor
的方法,它将颜色作为字符串,一个将名称作为字符串的方法GetCatsByName
,以及GetCatsByBirthDate
,该方法需要两个DateTime
作为时间范围。
现在假设我有一个CatFilter
类,其中包含List
名称、List
颜色和两个DateTime
,表示时间跨度的"开始"日期和"结束"日期。我正在尝试做的是创建一个GetFilteredCats
方法,该方法采用这些Filter
对象之一并返回符合给定Filter
规范的 Cat 集合。
我很难想出一种获得所需结果的有效方法,理想情况下使用 LINQ/lambda 表达式。
进行这种加入的最佳方法是什么?我应该查看哪些扩展方法?在foreach
循环中修改集合通常是不可取/不可能的,那么我的策略应该是什么?
我通常做的是在 where 子句中进行检查,该子句在执行实际过滤器之前检查是否需要过滤器。当运行时需要评估筛选器时,如果不需要筛选器,则会完全跳过它。
public class CatFilter
{
public List<string> Names = new List<string>();
public List<string> Colors = new List<string>();
public DateTime? BirthDateStartRange = null;
public DateTime? BirthDateEndRange = null;
}
public List<Cat> GetFilteredCats(CatFilter filter)
{
List<Cat> result = new List<Cat>();
var query = cats
.Where(a => !filter.Names.Any() || filter.Names.Contains(a.Name))
.Where(a => !filter.Colors.Any() || filter.Colors.Contains(a.Color))
.Where(a => filter.BirthDateStartRange == null || a.DateOfBirth >= filter.BirthDateStartRange)
.Where(a => filter.BirthDateEndRange == null || a.DateOfBirth <= filter.BirthDateEndRange);
result.AddRange(query);
return result;
}
然后这样称呼它
cats.Add(new Cat("Felix", "Black", DateTime.Today.AddDays(-1)));
cats.Add(new Cat("Garfield", "Orange", DateTime.Today.AddDays(-10)));
CatFilter filter = new CatFilter();
filter.Names.Add("Garfield");
List<Cat> result = GetFilteredCats(filter);
正确的方法是使方法GetFilteredCats
,接受您的过滤器并通过 LINQ 组合返回正确的猫:
IEnumerable<Cat> cats = //.. get all cats here
if (filter.FilterByColor)
cats = cats.Where(c=>c.Color = filter.Color);
if (filter.FilterByName)
cats = cats.Where(c=>c.Name = filter.Name);
if (filter.FilterByDate)
cats = cats.Where(c=>c.Date > filter.FromDate && c.Date < filter.ToDate)
return cats.ToList(); // finally filter data and return them.
在性能的情况下。我认为这在逻辑上不能使用不同的 aproach 来完成。但是当你开始打成群的猫时,这将成为一个问题。此时,应改用数据库。为了方便起见,它们具有巧妙的索引和聚类。
这样的东西应该可以工作,请注意它没有经过测试
List<string> names = new List<string>();
List<Color> colors = new List<Color>();
List<DateTime> dobs = new List<DateTime>();
List<cat> cats = new List<cat>();
var filtered = from c in cats
join n in names on c.name equals n
join cl in colors on c.color equals cl
join db in dobs on c.dob equals db
select c;
你也可以有一些包含两个日期的列表,在这种情况下,你需要输入一个where条件,其中c.dob <= date1 && c.dob>= date2,或类似的东西。希望这有帮助。
您可以使用表达式树。当 CatFilter 对象传递给 GetFilteredCats 方法时,根据在此对象上设置的属性,生成表达式(即 在下面的伪代码中看到),您可以连接并用于构建完整的 LINQ 查询。
像这样:
Expression catFilter =
from cat in Cats
where <Expression> and <Expression> and ...
select cat
然后简单地编译(Expression.Compile)并执行。