2014-02-10 110 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,即使謂語建造者是對我的方案一個恰當的解決方案。