简体   繁体   English

为什么Linq不提供lambda参数而不是IEqualityComparer <T> ?

[英]Why does Linq not provide a lambda parameter instead of IEqualityComparer<T>?

So in things like GroupBy() in Linq, you can provide an implementation of IEqualityComparer<T> to help with object comparisons. 因此,在Linq中的GroupBy()类的东西中,您可以提供IEqualityComparer<T>来帮助进行对象比较。 It seems, though, that it would be easier to simply pass in a lambda expression. 但是,似乎简单地传入lambda表达式会更容易。

Example: 例:

// current implementation
myCollection.GroupBy(c => c.Foo, c => c.Bar, new FooBarComparer());

// it seems easier to...
myCollection.GroupBy(c => c.Foo, c => c.Bar, (x, y) => x.Baz == y.Baz);

Given a simple implementation of IEqualityComparer<T> like this: 给出IEqualityComparer<T>的简单实现,如下所示:

public class FooBarComparer : IEqualityComparer<FooBar> {
    public bool Equals(FooBar x, FooBar y) {
        return x.Baz == y.Baz;
    }

    public int GetHashCode(FooBar obj) {
        return obj.GetHashCode();
    }
}

It seems that providing a lambda expression could be just as effective. 似乎提供lambda表达式同样有效。 As it stands now, if I try to pass in an IEqualityComparer<T> with a Linq query to a database, it fails because SQL Server (or whatever) doesn't know anything about my class. 就像现在一样,如果我尝试将带有Linq查询的IEqualityComparer<T>传递给数据库,它会失败,因为SQL Server(或其他)对我的类一无所知。 It seems that a lambda would be able to be translated into SQL that can be used in the target database. 看起来lambda能够被翻译成可以在目标数据库中使用的SQL。

Is there a specific reason this is not provided as an option in Linq? 是否有一个特定的原因在Linq中没有提供这个选项?

You'd need two lambdas so that GetHashCode has an equivalent as well. 你需要两个lambdas,以便GetHashCode也有一个等价物。 Besides that this would work, yes. 除此之外,这可行,是的。 There are some LINQ methods that do not make use of hash codes but that use equality ( Enumerable.Contains ). 有一些LINQ方法不使用哈希码但使用相等( Enumerable.Contains )。

I guess it's just to have a standard API for equality that the whole BCL uses. 我想这只是一个标准的API,用于整个BCL使用的相等性。 You can easily convert between delegate and comparer by using a delegate-backed comparer implementation or by converting myComparer.Equals to a delegate. 您可以使用委托支持的比较器实现或将myComparer.Equals转换为委托,轻松地在委托和比较器之间进行转换。

For remoting expressions to the database is is not easy to remote a comparer expression. 对于将表达式远程连接到数据库,远程比较器表达式并不容易。 GROUP BY does not support that in SQL. GROUP BY在SQL中不支持。 It can surely be made to work but it is a niche use case (actually if the comparer expression for a GroupBy does not provide an equality relation I'm not sure how that would turn out when translated to SQL). 它肯定可以工作,但它是一个利基用例(实际上,如果GroupBy的比较器表达式不提供相等关系,我不确定在转换为SQL时会是什么结果)。

To make an efficient GroupBy / Distinct you need two things: 要创建有效的GroupBy / Distinct您需要两件事:

  • An equality comparer 一个相等比较器
  • An hash generator, to create an hash dictionary 一个哈希生成器,用于创建哈希字典

OR you can follow the C++ route 或者您可以遵循C ++路线

  • A comparator able to order the elements, so that you are able to create a tree 比较器能够对元素进行排序,以便您能够创建树

If you only have an equality comparer, then the difficulty of doing the GroupBy is something like O(n^2) , because if you have 5 elements, you need 5 + 4 + 3 + 2 + 1 comparisons, so n * (n + 1) / 2 so 15. This is something a "good" library wouldn't ever permit you to do (and no sane SQL server would ever do!) 如果你只有一个相等比较器,那么做GroupBy的难度就像O(n ^ 2) ,因为如果你有5个元素,你需要5 + 4 + 3 + 2 + 1比较,所以n *(n + 1)/ 2所以15.这是一个“好”的库不会允许你做的事情(没有理智的SQL服务器会做!)

Now, clearly the LINQ library could analyze your equality lambda, see that it is 现在,显然LINQ库可以分析你的相等lambda,看看它是什么

(x, y) => x.Baz == y.Baz

see that it is symmetrical, so that the left term and the right term are in the form 看它是对称的,所以左边的术语和右边的术语都是对称的

x => x.Baz

and use this to generate an hasher and select a comparer. 并使用它来生成一个哈希并选择一个比较器。 But at this point, wouldn't it be easier to do directly 但在这一点上,直接做是不是更容易

myCollection.GroupBy(c => c.Foo.Baz) 

Yes, that you can do :-) 是的,你可以这样做:-)

And then, 接着,

myCollection.GroupBy(c => c.Foo.Baz, c => new { c.Foo, c.Bar })
            .Select(c => new { Key = c.First().Foo, Values = c.Select(x => x.Bar) })

That is quite similar to your intended GroupBy (the only difference is that the values are in a Values IEnumerable<> ) 这与您想要的GroupBy非常相似(唯一的区别是值在Values IEnumerable<>

Now... for the use of the overloads with IEqualityComparer<T> ... as I've written in the comments, I do think that they should be used with "stock" comparers, that the LINQ provider can recognize, like the various StringComparer.* (eg StringComparer.OrdinalIgnoreCase ) and the EqualityComparer<T>.Default , that represents the "default" comparer. 现在......对于使用IEqualityComparer<T>的重载...正如我在评论中写的那样,我认为它们应该与“库存”比较器一起使用,LINQ提供者可以识别,就像各种StringComparer.* (例如StringComparer.OrdinalIgnoreCase )和EqualityComparer<T>.Default ,表示“默认”比较器。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM