简体   繁体   English

Linq代码重构

[英]Linq code refactoring

Please help me to refactor this code using Linq. 请帮助我使用Linq重构此代码。 How to use Where and ToList only once? 如何只使用一次Where和ToList? Thx for help 寻求帮助

private IEnumerable<SomeClass> Filter(IEnumerable<SomeClass> aaa, string name, string company, string address,int? age)       
{
    var ans = new List<SomeClass>();         
    if (!String.IsNullOrEmpty(name))
        ans = aaa.Where(x => x.name.equal(name)).ToList();

    if (!String.IsNullOrEmpty(company))
        ans = ans.Where(x => x.company.equal(company)).ToList();

    if (!String.IsNullOrEmpty(address))
        ans = ans.Where(x => x.address.equal(address)).ToList();

    if (age.HasValue)
        ans = ans.Where(x => x.age == age.Value).ToList();

    return ans;
}

You could use this: 您可以使用此:

var ans = aaa.Where( x => ( string.IsNullOrEmpty(name)
                            || x.name.equal(name)
                          )
                          &&
                          ( string.IsNullOrEmpty(company)
                            || x.company.equal(company)
                          )
                          &&
                          ( string.IsNullOrEmpty(address)
                            || x.address.equal(address)
                          )
                          &&
                          ( !age.HasValue
                            || x.age == age.Value
                          )
                   );

You can drop all calls to ToList . 您可以放弃对ToList所有呼叫。 Without those calls, the combined filtering will be executed in a deferred way that you don't need to care about. 没有这些调用,组合过滤将以您不需要关心的延迟方式执行。

If you do want to influence the time at which filtering is executed (or make sure the result is based on the snapshot of aaa at the time of invocation of Filter and does not change if aaa changes later on), change your last line to 如果您确实想影响执行过滤的时间(或确保结果基于调用Filteraaa的快照,并且在以后更改aaa不改变),请将最后一行更改为

return ans.ToArray();

(a list is probably not necessary here; the returned value is typed to IEnumerable<SomeClass> anyway and callers shouldn't expect to be able to directly modify (add/remove items) the returned object. (这里可能不需要列表;无论如何,返回值都键入IEnumerable<SomeClass> ,并且调用者不应期望能够直接修改(添加/删除项)返回的对象。

Thus, the complete code would look like this: 因此,完整的代码如下所示:

private IEnumerable<SomeClass> Filter(IEnumerable<SomeClass> aaa, string name, string company, string address,int? age)       
{
    IEnumerable<SomeClass> ans = new SomeClass[0];
    if (!String.IsNullOrEmpty(name))
        ans = aaa.Where(x => x.name.Equals(name));

    if (!String.IsNullOrEmpty(company))
        ans = ans.Where(x => x.company.Equals(company));

    if (!String.IsNullOrEmpty(address))
        ans = ans.Where(x => x.address.Equals(address));

    if (age.HasValue)
        ans = ans.Where(x => x.age == age.Value);

    return ans.ToArray();
}

As other answers have shown, it is also possible to combine all Where calls into one, though sticking with your original chain of if s and Where s shows very clearly what it does, which might not be true for the combined solutions. 正如其他答案所表明的那样,也可以将所有Where调用合并到一个中,尽管坚持使用if s和Where s的原始链可以很清楚地显示出它的作用,这对于合并的解决方案可能并非如此。

Just to add another answer here. 只是在这里添加另一个答案。 Why create a List at all your input is an IEnumerable and so is your output is the same? 为什么在所有输入中创建一个列表都是IEnumerable,所以输出是否相同?

private IEnumerable<SomeClass> Filter(IEnumerable<SomeClass> aaa, string name, string company, string address, int? age)
{
    if (!String.IsNullOrEmpty(name))
        aaa = aaa.Where(x => x.name.Equals(name));

    if (!String.IsNullOrEmpty(company))
        aaa = aaa.Where(x => x.company.Equals(company));

    if (!String.IsNullOrEmpty(address))
        aaa = aaa.Where(x => x.address.Equals(address));

    if (age.HasValue)
        aaa = aaa.Where(x => x.age == age.Value);

    return aaa;
}

My two cents on the subject: 我在这个问题上的两分钱:

  1. I don't think you need to simplify the method to one Where clause because if you keep it this way, you can easily add new filter parameters later and your code would be quite readable. 我认为您不需要将方法简化为一个Where子句,因为如果您以这种方式保留它,则以后可以轻松添加新的过滤器参数,并且您的代码将易于阅读。
  2. You don't need to specify ToList() . 您无需指定ToList()
  3. Instead of String.IsNullOrEmpty() consider using String.IsNullOrWhiteSpace() . 取而代之的String.IsNullOrEmpty()考虑使用String.IsNullOrWhiteSpace() This way, you will not filter out entities if a non-empty but whitespace string is provided. 这样,如果提供了非空但空白的字符串,则不会过滤掉实体。
  4. Instead of x.name.Equals(name) consider using x.name.Equals(name, StringComparison.InvariantCultureIgnoreCase) if appropriate. 如果合适x.name.Equals(name, StringComparison.InvariantCultureIgnoreCase)考虑使用x.name.Equals(name, StringComparison.InvariantCultureIgnoreCase)代替x.name.Equals(name)

You could do something like this: 您可以执行以下操作:

var ans = aaa.Where(x => !string.IsNullOrEmpty(name) ? x.name.equal(name) : false).ToList()
             .Union(aaa.Where(x => !string.IsNullOrEmpty(company) ? x.company.equal(company) : false).ToList())
             .Union(aaa.Where(x => !string.IsNullOrEmpty(address) ? x.address.equal(address) : false).ToList());

ans = ans.Where(x => age.HasValue ? x.age == age.Value : true).ToList();

You should try something like this : 您应该尝试这样的事情:

private static IEnumerable<SomeClass> Filter(IEnumerable<SomeClass> aaa, string name, string company, string address, int? age)
{

        var ans = aaa.Where(x => !String.IsNullOrEmpty(name) ? x.Name.Equals(name) : true)
                 .Where(x => !String.IsNullOrEmpty(company) ? x.Company.Equals(company) : true
                     && !String.IsNullOrEmpty(address) ? x.Address.Equals(address) : true
                     && age.HasValue ? x.Age == age.Value : true);


        return ans;
} 

But note that in your code, you always return 0 results if the "name" parameter is empty. 但是请注意,在您的代码中,如果“ name”参数为空,则始终返回0个结果。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM