2014-01-07 131 views
1

请帮我使用Linq重构此代码。如何只使用Where和ToList一次? THX求助Linq代码重构

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

您可以在此处使用Expression > exp create以下每个条件。代码如下:ans = ans.Where(exp)。ToList() –

+1

这是一个奇怪的方法;如果为'name'提供'null',但为其他参数提供实际值,'ans'将仍为空。我怀疑这就是你想要发生的事情。 – Rik

回答

3

您可以使用此:

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

'.ToList()'不是绝对必要的,因为方法返回'IEnumerable <>'。 – Rik

0

你可以做这样的事情:

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

将问题中的过滤器组合在一起。如果我没有弄错的话,你们将它们结合在一起。 –

+0

@ O.R.Mapper更新了我的答案 – RononDex

+0

我认为这是一个坏主意性能明智,因为你迭代列表多次。 –

1

可以删除所有呼叫ToList。如果没有这些调用,组合的过滤将以一种您不需要关心的延迟方式执行。

如果你想影响在被执行过滤的时间(或确保结果是基于aaaFilter调用时的快照,如果aaa变化以后不改),更改最后一行

return ans.ToArray(); 

(名单可能没有必要在这里;返回值的类型不是IEnumerable<SomeClass>不管怎样,主叫方不应该期望能够直接修改(添加/删除项)返回的对象

因此,完整的代码应该是这样的:

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

至于其他的答案显示,也可以将所有Where呼叫组合成一个,虽然与你原来的if的连锁和Where小号表演粘得很清楚它做什么,这对于组合解决方案可能不是这样。

+0

O.R Mapper ..此代码不编译。 'equal'应该是'Equals',并且您试图将'IEnumerable <>'转换为'List <>',您的代码必须在每个语句后调用'ToList()'扩展方法才能编译。另外,为什么要返回'ToArray()'这将强制'IEnumerable <>'的枚举只是转回到'IEnumerable <>'只需几个注释。 – Nico

+0

@Nico:谢谢,我在复制问题的代码时过于热情,这就是'equal'是如何创建的。我已经将'ans'的类型改为这里足够的东西。至于'ToArray()',正如我在答案中所解释的那样,强制立即枚举可能也可能不需要,这取决于对作为'aaa'传递的集合的后续更改是否应该反映在返回的枚举中。 –

1

只是在这里添加另一个答案。为什么在你的输入中创建一个List是一个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; 
} 
+0

这与OP的代码略有不同:如果没有应用过滤器,原始代码将返回一个空枚举,而您的将返回整个'aaa'枚举。不过,不确定这种行为是否被OP所打算。 –

0

你应该尝试这样的事:

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

但需要注意的是,在你的代码,你总是返回0的结果,如果“名”参数为空。

1

关于这个问题我的两分钱:

  1. 我不认为你需要简化的方法来一个Where子句,因为如果你把这种方式,以后可以轻松添加新的筛选器参数和您的代码会很可读。您不需要指定ToList()
  2. 而不是String.IsNullOrEmpty()考虑使用String.IsNullOrWhiteSpace()。这样,如果提供非空但空白字符串,则不会过滤掉实体。
  3. 而不是x.name.Equals(name)考虑使用x.name.Equals(name, StringComparison.InvariantCultureIgnoreCase)如果适当。