2013-02-04 100 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; } 
    } 
}