我可以使用Linq的Except()和lambda表达式比较器吗?

我知道我可以调用linq的Except并指定一个自定义的IEqualityComparer,但是为每个数据类型实现一个新的Comparer类似乎是一种过度的方法。 我可以使用lambda表达式来提供相等的函数,就像我使用Where或其他LINQ函数一样吗?

如果我不能,还有其他选择吗?

我不认为你可以直接使用基本的LINQ接口,但是我看到人们用扩展方法实现一个LambdaComparer类,这将有助于你做到这一点。

这是一个例子

对于任何仍在寻找的人; 这是实现自定义lambda比较器的另一种方法。

public class LambdaComparer : IEqualityComparer { private readonly Func _expression; public LambdaComparer(Func lambda) { _expression = lambda; } public bool Equals(T x, T y) { return _expression(x, y); } public int GetHashCode(T obj) { /* If you just return 0 for the hash the Equals comparer will kick in. The underlying evaluation checks the hash and then short circuits the evaluation if it is false. Otherwise, it checks the Equals. If you force the hash to be true (by assuming 0 for both objects), you will always fall through to the Equals check which is what we are always going for. */ return 0; } } 

然后你可以为linq创建一个扩展,除了一个接受lambda的相交

 ///  /// Returns all items in the first collection except the ones in the second collection that match the lambda condition ///  /// The type /// The first list /// The second list /// The filter expression /// The filtered list public static IEnumerable Except(this IEnumerable listA, IEnumerable listB, Func lambda) { return listA.Except(listB, new LambdaComparer(lambda)); } ///  /// Returns all items in the first collection that intersect the ones in the second collection that match the lambda condition ///  /// The type /// The first list /// The second list /// The filter expression /// The filtered list public static IEnumerable Intersect(this IEnumerable listA, IEnumerable listB, Func lambda) { return listA.Intersect(listB, new LambdaComparer(lambda)); } 

用法:

 var availableItems = allItems.Except(filterItems, (p, p1) => p.Id== p1.Id); 

你能不能使用带有过滤掉你所需值的lambda的。

请求示例:

  static void Main(string[] args) { var firstCustomers = new[] { new Customer { Id = 1, Name = "Bob" }, new Customer { Id = 2, Name = "Steve" } }; var secondCustomers = new[] { new Customer { Id = 2, Name = "Steve" }, new Customer { Id = 3, Name = "John" } }; var customers = secondCustomers.Where(c => !firstCustomers.Select(fc => fc.Id).Contains(c.Id)); } public class Customer { public int Id { get; set; } public string Name { get; set; } } 

这是我掀起的简单事情:

 public class CustomComparer : IEqualityComparer where TSource : class { private readonly Func getComparisonObject; public CustomComparer(Func getComparisonObject) { if (getComparisonObject == null) throw new ArgumentNullException("getComparisonObject"); this.getComparisonObject = getComparisonObject; } ///  /// Determines whether the specified objects are equal. ///  ///  /// true if the specified objects are equal; otherwise, false. ///  /// The first object of type  to compare. /// The second object of type  to compare. ///  public bool Equals(TSource x, TSource y) { if (x == null) { return (y == null); } else if (y == null) { return false; } return EqualityComparer.Default.Equals(getComparisonObject(x), getComparisonObject(y)); } ///  /// Returns a hash code for the specified object. ///  ///  /// A hash code for the specified object. ///  /// The  for which a hash code is to be returned. /// The type of  is a reference type and  is null. ///  public int GetHashCode(TSource obj) { return EqualityComparer.Default.GetHashCode(getComparisonObject(obj)); } } 

用法:

 var myItems = allItems.Except(theirItems, new CustomComparer(item => item.Name)); 

使用扩展名 !

 public static IEnumerable Except(this IEnumerable items, IEnumerable other, Func getKey) { return from item in items join otherItem in other on getKey(item) equals getKey(otherItem) into tempItems from temp in tempItems.DefaultIfEmpty() where ReferenceEquals(null, temp) || temp.Equals(default(T)) select item; } 

资源

这是’ 除了r解决方案,基于LINQ外连接技术:

 from l in new[] { 1, 2, 3 } join r in new[] { 2, 4, 5 } on l equals r into rr where !rr.Any() select l 

将产量:1,3

但你可以试试这个。 这很容易,我认为代码包含错误。 当然,代码是少量的,没有LINQ转换为db等。

 public static IEnumerable ExceptPredicate(this IEnumerable first, IEnumerable second, Func compare) { foreach (var itmFirst in first) { if (!second.Any(itmsecond => compare(itmFirst, itmsecond))) { yield return itmFirst; } } yield break; }