我可以将对象的属性与要处理的对象一起传递吗?

时间:2020-02-04 12:00:27

标签: c#

我使用IQueryable<Person>类的实例在Person上有一个顺序过滤器,运行方式如下:

    public IQueryable<Person> FilterPeopleOnPersonCriteria(IQueryable<Person> people, Person p)
    {
        if (!string.IsNullOrEmpty(p.FirstName))
        {
            people = people.Where(x => x.FirstName == p.FirstName);
        }

        if (!string.IsNullOrEmpty(p.Surname))
        {
            people = people.Where(x => x.Surname == p.Surname);
        }
        // etc. for all Person's string properties

        return people;
    }

我想如果可以通过peoplePerson和我想申请的property,就可以烘干自己并替换if / else的重复项过滤器转换为特定的过滤器方法,如下所示:

    public IQueryable<Person> FilterPeopleOnProperty(IQueryable<Person> people, Person p, Person.Property personProperty)
    {
        if (!string.IsNullOrEmpty(p.personProperty))
        {
            people = people.Where(x => x.personProperty == p.personProperty);
        }
        return people;
    }

最后,我的原始查询如下:

    public IQueryable<Person> FilterPeopleOnPersonCriteria(IQueryable<Person> people, Person p)
    {
        people = FilterPeopleOnPersonProperty(people, p, new Person().FirstName);
        people = FilterPeopleOnPersonProperty(people, p, new Person().Surname);
        // etc. for all properties on p
        return people;
    }

我假设使用某些通用类型和我的Person类的新实例是可能的,但不知道从哪里开始。

2 个答案:

答案 0 :(得分:1)

我想这就是您要寻找的东西

namespace Extensions
{
    using System;
    using System.Linq;
    using System.Collections.Generic;

    public static class IEnumerableExtensions
    {
        public static IEnumerable<T> WhereIf<T>(this IEnumerable<T> collection, bool condition, Func<T, bool> predicate)
        {
            return condition ? collection.Where(predicate) : collection;
        }
    }
}

仅当条件为真时,我们才进行过滤。我使用IEnumerable<T>是因为它更通用,并且还是由IQueryable<T>实现的,但是您仍然可以使用IQueryable<T>来代替。如果您想使用IQueryable<T>,则需要使用System.Linq.Expressions,并用Func<T, bool>替换Expression<Func<T, bool>>

与您的用例类似的用例如下:

public IEnumerable<Person> FilterPeople(IEnumerable<Person> people, Person person)
{
    return people.WhereIf(!string.IsNullOrEmpty(person.FullName), p => p.FullName == person.FullName);
}

答案 1 :(得分:1)

如果我理解您的要求是正确的,那么您想传递一个Person对象,其中填充了一些(字符串)属性,例如“ Starts *”,“ * ends”,“ ExactValue”,并且您将该Person用作QBE(按示例查询。即:

Person p = new Person {FirstName="S*", LastName="*doe", Country="USA"};

将进行以下搜索:

people.Where(p => p.FirstName.StartsWith("S") &&
                  p.LastName.EndsWith("doe") &&
                  p.Country == "USA");

对吗?如果是这样,那么我认为您可以利用Scott Gu's dynamic Linq,一些好人可以在NuGet和documented here上找到他们。

以下是使用该Nuget库(System.Linq.Dynamic)的一些示例代码:

public IQueryable<Person> FilterPeopleOnPersonCriteria(IQueryable<Person> people, Person p)
{
    var t = p.GetType();
    var fields = t
        .GetFields()
        .Where(x => x.FieldType == typeof(string) &&
        !string.IsNullOrEmpty((string)t.GetField(x.Name).GetValue(p)))
        .Select(x => x.Name);
    foreach (var f in fields)
    {
        var fi = t.GetField(f);
        string pVal = (string)fi.GetValue(p);
        if (pVal.Contains('*'))
        {
            var query = $"{f}.{(pVal.StartsWith("*") ? "Ends" : "Starts")}With(@0)";
            people = people.Where(query, pVal.Replace("*", ""));
        }
        else
        {
            var query = $"{f} == @0";
            people = people.Where(query, pVal);
        }
    }
    return people;
}

您会这样称呼它:

var personQBE = new Person {
                  FirstName="J*",
                  LastName="Doe"
                });  

var result = FilterPeopleOnPersonCriteria(people, personQBE);