2014-02-10 139 views
1

我有一个List<Device>。在Device类中有4个属性,即NameOperatingSystem,StatusLastLoggedInUser。我需要写一个方法:使用Linq进行动态过滤

IQueryable<Device> FilterDeviceList(
    List<Device> Devices, 
    List<string> 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) 

}` 
+0

if语句你总是可以做到这一点,但我不知道它是否能与动态LINQ来完成。 –

回答

8

你可以建立你的查询,如下所示:

private static IQueryable<Device> FilterDeviceList(List<Device> 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" 
      }); 

编辑,对name属性过滤器:

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

编辑2,来看看predicatebuilder

var predicate = PredicateBuilder.False<Device>(); 

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); 
+0

有趣的想法。我喜欢。 –

+0

@dieter感谢您的快速回复。我已经编辑,请ü可以看看,我需要acheive是 – wintersolider

+0

在我的例子,你并不需要一个“过滤器”列表中。如果您要包含的一切,只是通过与所有填写的性质在一个对象,如果要筛选只是名字,传递一个对象只是属性名填写。 – Dieterg

0

你已经基本上2种选择:

  1. 使用System.Linq.Expression API来构建LINQ谓词(大量的工作,但如果使用得当一个很好的可重用解决方案)。您仍然需要映射过滤器名称和属性(例如,名称相同)
  2. 将过滤器名称与您的Func<TObject, TFilterValue, bool>谓词之间的映射进行硬编码。你可以在一个静态字典(或普通的旧开关)中做到这一点。只要确保你在谓词上创建了一个闭包并绑定你的过滤值。在哪里调用需要一个Func<T, bool>
6

你可以做这样的事情:

public IEnumerable<Device> FilterDevices(IEnumerable<Device> devices, IEnumerable<Func<Device, string>> 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<Device> 
{ 
    new Device { OS = "Windows", Name = "Foo" }, 
    new Device { OS = "Mac", Name = "Bar" } 
}; 

var filters = new List<Func<Device, string>> 
{ 
    d => d.OS 
}; 

var result = FilterDevices(devices, filters, "Windows"); 

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

0
private IQueryable<Device> FilterCentraStageDeviceList(List<Device> centraStageDevices, string filter, string filterValue) 
    { 
     IQueryable<Device> alldevices = centraStageDevices.AsQueryable<Device>(); 
     IQueryable<Device> query = new List<Device>().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,即使谓语建造者是对我的方案一个恰当的解决方案。