使用Linq进行动态过滤

我有一个List 。 在Device类中有4个属性,即NameOperatingSystemStatusLastLoggedInUser 。 我需要写一个方法:

 IQueryable FilterDeviceList( List Devices, List filter, string filterValue) 

其中filter将包含用于过滤"name""os"选项,以指示要包含在搜索中的字段。 如果传递"all"则需要包括所有4个字段。 filtervalue将包含要过滤的值,如"windows""Calvin"

谁能建议一种方法来实现这一目标?

编辑:

如果我不清楚,我做的过滤有点像这样,它是我需要代码的注释部分。

 if(filter.contains(name)) { //filter with name } if( filter.contains(both name and os) { // I only need the filter value to contain in name or OS (only needed in any one of the field,not necessary to be in both) }` 

您可以按如下方式构建查询:

 private static IQueryable FilterDeviceList(List devices, Device device) { var query = devices.AsQueryable(); if (device.Name != null) query = query.Where(d => d.Name == device.Name); if (device.OS != null) query = query.Where(d => d.OS == device.OS); if (device.Status != null) query = query.Where(d => d.Status == device.Status); if (device.LastLoggedInUser != null) query = query.Where(d => d.LastLoggedInUser == device.LastLoggedInUser); return query; } 

然后,您可以使用设备对象调用此函数。 即如果你想要包含名称,只需传递一个带有名称的设备对象(将其他属性保留为默认值)。 如果您希望包含所有内容,请传入设备对象,其中包含所有内容:

 var r = FilterDeviceList(devices, new Device { Name = "yourFilterValue", OS = "yourFilterValue", LastLoggedInUser = "yourFilterValue", Status = "yourFilterValue" }); 

编辑,过滤名称属性:

 var r = FilterDeviceList(devices, new Device { Name = "yourFilterValue" }); 

编辑2,看看谓词构建器

 var predicate = PredicateBuilder.False(); if(document.Name != null) predicate = predicate.Or(d => d.Name == document.Name); if(document.OS != null) predicate = predicate.Or(d => d.OS == document.OS); return devices.Where(predicate); 

你可以这样做:

 public IEnumerable FilterDevices(IEnumerable devices, IEnumerable> filters, string filterValue) { foreach (var filter in filters) { devices = devices.Where(d => filter(d).Equals(filterValue)); } return devices; } 

附:

 public class Device { public string Name { get; set; } public string OS { get; set; } } 

用法:

 var devices = new List { new Device { OS = "Windows", Name = "Foo" }, new Device { OS = "Mac", Name = "Bar" } }; var filters = new List> { d => d.OS }; var result = FilterDevices(devices, filters, "Windows"); 

这只是一个粗略的想法 – 根据需要转换为您的解决方案!

你基本上有两个选择:

  1. 使用System.Linq.Expression API来构建LINQ谓词(如果做得好的话,可以使用很多可重用的解决方案)。 您仍然需要在某些内容上映射filter名称和属性(例如,相同的名称)
  2. 硬编码filter名称与Func谓词之间的映射。 您可以在静态字典(或普通旧字典)中执行此操作。 只需确保在谓词上创建闭包并绑定filter值。 Where调用期望Func
 private IQueryable FilterCentraStageDeviceList(List centraStageDevices, string filter, string filterValue) { IQueryable alldevices = centraStageDevices.AsQueryable(); IQueryable query = new List().AsQueryable(); if (filter == null || string.IsNullOrEmpty(filterValue)) { return alldevices; } filterValue = filterValue.ToLower(); var filterLower = filter.ToLower(); if (filterLower.Contains("all") || (filterLower.Contains("hostname") && filterLower.Contains("operatingsystem") && filterLower.Contains("status") && filterLower.Contains("lastloggedinuser"))) { return alldevices.Where(x => checkNull(x.Name).Contains(filterValue) || checkNull(x.OperatingSystem).Contains(filterValue) || checkNull(x.LastUser).Contains(filterValue)); } if (filterLower.Contains("hostname")) { query = alldevices.Where(x => checkNull(x.Name).Contains(filterValue)); } if (filterLower.Contains("operatingsystem")) { query = alldevices.Where(x => checkNull(x.OperatingSystem).Contains(filterValue)).Union(query); } if (filterLower.Contains("lastloggedinuser")) { query = alldevices.Where(x => checkNull(x.LastUser).Contains(filterValue)).Union(query); } return query; } 

这是我最后使用的,因为我不允许使用外部dll,即使谓词构建器是我的场景的适当解决方案。