2014-01-07 183 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)如果適當。