使用Linq进行动态过滤

时间:2014-02-10 11:11:04

标签: c# linq

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

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)

}`

4 个答案:

答案 0 :(得分:12)

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

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"
            });

编辑,过滤名称属性:

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

答案 1 :(得分: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");

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

答案 2 :(得分:0)

你基本上有两个选择:

  1. 使用System.Linq.Expression API构建您的LINQ谓词(如果做得好,可以使用很多可行的解决方案)。您仍然需要在某些内容上映射过滤器名称和属性(例如,同名)
  2. 对过滤器名称与Func<TObject, TFilterValue, bool>谓词之间的映射进行硬编码。您可以在静态字典(或普通旧字典)中执行此操作。只需确保在谓词上创建闭包并绑定过滤器值。 Where调用需要Func<T, bool>

答案 3 :(得分: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,即使谓词构建器是我的场景的适当解决方案。