2013-02-04 102 views
1

我有一個方法,除了一個IEnumerable<T>和一個lambda表達式,它描述了用來比較一個linq-to-sql集合到一個數組的字段。該方法返回匹配的記錄。匿名方法的問題

public IEnumerable<ZipCode> match<T>(IEnumerable<T> values, 
     Func<ZipCode, T> matchPhrase) { 
    return (from zipCode in _table 
      where values.Contains<T>(matchPhrase) 
      select zipCode).Distinct(); 
} 

,我發現了錯誤:

Argument type 'Func<ZipCode, T>' is not assignable to parameter type 'T'

的方法將被稱爲像這樣(其中valuesIEnumerable<string>x.zipcodestring):

var zipCodes = _zipCodeRepository.match(values, x => x.zipcode) 

UPDATE

基於使用HashSet<T>約翰的建議,我已經改變了我的代碼,但我得到一個不同的錯誤,現在

Method 'System.Object DynamicInvoke(System.Object[])' has no supported translation to SQL.

我想我可能不會一直在清楚我的問題,我想我用錯了方法簽名來獲得我想要的結果。讓我用一個更簡單的代碼示例來解釋:

public IEnumerable<ZipCode> match(IEnumerable<string> values) { 
    return (from zipCode in _table 
      where values.Contains(zipCode.zipcode) 
      select zipCode).Distinct(); 
} 

我打算完成此操作,但使用匿名類型。我想通過lambda來通過在Contains()中使用的字段。所以zipCode.zipcode將被傳遞到方法的第二個參數:x => x.zipcode

+1

你幾乎肯定希望把'values'成'HashSet'在一開始,這樣就可以更有效地搜索它。因爲它是枚舉'values',對'_table'中的每個項目進行線性搜索。這是非常低效的,並且可重複枚舉多次,這真的應該在這樣的函數中避免。 – Servy

回答

2

我懷疑你想致電代表:

return (from zipCode in _table 
     where values.Contains(matchPhrase(zipCode)) 
     select zipCode).Distinct(); 

請注意,這可能會非常昂貴。您可能需要先創建一組:

HashSet<T> valueSet = new HashSet<T>(values); 
return _table.Where(x => valueSet.Contains(matchPhrase(x)) 
      .Distinct(); 

(我已經在這裏刪除的查詢表達式,因爲它是在可讀性方面做弊大於利。)

+0

請編輯上面的第二個參數名稱 – bflemi3

+1

@ bflemi3我剛剛建議您不要將函數的參數命名爲與方法本身相同的名稱......這可能會導致混淆。 – Servy

+0

@JonSkeet爲什麼使用_HashSet_,然後使用_Where_和_Contains_,而LINQ連接方法以更高性能的方式完成此任務? –

1

您在Contains

public IEnumerable<ZipCode> match<T>(IEnumerable<T> values, Func<ZipCode, T> matchPhrase) { 
    return (from zipCode in _table 
      where values.Contains(matchPhrase(zipCode)) // <- Here (and you don't need to specify <T>, the compiler deduce it from the argument) 
      select zipCode).Distinct(); 
} 

忘記(zipCode)您可以使用加入方法有更好的表現(在O(n)複雜性):

public IEnumerable<ZipCode> match<T>(IEnumerable<T> values, Func<ZipCode, T> matchPhrase) 
{ 
    return (from zipCode in _table 
      join value in values on matchPhrase(zipCode) equals value 
      select zipCode).Distinct(); 
} 
+0

'match' *是*函數,並且包含根本不接受函數。 – Servy

+0

@Servy我已經修復了它 –

+0

請參閱編輯第二個參數名稱 – bflemi3

1

只包含接受字符串作爲參數,而不是表達式。您無法在此級別上對其進行參數設置。

你可以通過在全部分地方作爲參數:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Linq.Expressions; 

namespace ConsoleApplication 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      var values = new List<string>(); 
      values.Add("123"); 

      Console.WriteLine(
       Match(zip => values.Contains(zip.Code)).Count()); // -> 1 

      Console.WriteLine(
       Match(zip => values.Contains(zip.OtherCode)).Count()); // -> 0 

      Console.Read(); 
     } 

     public static IEnumerable<ZipCode> Match(Expression<Func<ZipCode, bool>> predicate) 
     { 
      var table = new List<ZipCode> 
         { new ZipCode { Code = "123" }, new ZipCode { OtherCode = "234" } } 
       .AsQueryable(); 

      return (from zipCode in table.Where(predicate) 
        select zipCode).Distinct(); 
     } 
    } 
    public class ZipCode 
    { 
     public string Code { get; set; } 

     public string OtherCode { get; set; } 
    } 
}