我如何对这段LINQ代码进行单元测试?
public static IEnumerable<T> Distinct<T, TKey>(this IEnumerable<T> items, Func<T, TKey> keySelector, IEqualityComparer<TKey> comparer)
{
return items.Distinct(new KeyEqualityComparer<T, TKey>(keySelector, comparer.Equals));
}
我不知道如何在最后使用比较器,这个用法是什么?
编辑:抱歉不清楚;
我想知道的是:
KeyEqualityComparer:
class KeyEqualityComparer<T, TResult>: IEqualityComparer<T>
{
private readonly Func<T, TResult> _KeySelector;
private readonly Func<TResult, TResult, bool> _Predicate;
public KeyEqualityComparer(Func<T, TResult> keySelector, Func<TResult, TResult, bool> predicate)
{
if (keySelector == null)
throw new ArgumentNullException("keySelector");
_KeySelector = keySelector;
_Predicate = predicate ?? System.Collections.Generic.EqualityComparer<TResult>.Default.Equals;
}
public bool Equals(T x, T y)
{
return _Predicate(_KeySelector(x), _KeySelector(y));
}
public int GetHashCode(T obj)
{
// Always return the same value to force the call to IEqualityComparer<T>.Equals
return 0;
}
}
答案 0 :(得分:5)
此代码尝试执行类似于MoreLINQ的DistinctBy
方法,但不是。
从根本上说,这个想法是,给定一组项目,你想要找到一个不同的项目,但是通过比较一些关键词的概念来专门测试不同性。例如,您可能有Person
类型,如下所示:
// TODO: Use C# 6 primary constructor and read-only autoprops :)
public class Person
{
public string Name { get; set; }
public string Hobby { get; set; }
public string Profession { get; set; }
}
使用这样的数据:
var people = new List<Person>
{
new Person { Name="Tom", Hobby="Minecraft", Profession = "Student" },
new Person { Name="Robin", Hobby="Taunting", Profession = "Outlaw" },
new Person { Name="Robin", Hobby="Angry Birds", Profession = "Student" },
};
现在我们可以通过名字(在这种情况下我们得到汤姆和其中一个罗宾斯)或专业(在这种情况下我们得到歹徒和其中一个学生)获得一组独特的人。我们可以额外指定在比较键时使用的相等比较器 - 例如,“TOM”和“Tom”可能被认为是相等的。
LINQ中的Distinct
方法已经允许您指定自定义相等比较器,因此您的Distinct
方法(顺便说一下,我不会重载)只是将项目项目设置为其键和用途给定的密钥相等比较器来比较这些密钥。
不幸的是,问题中给出的实现很糟糕:IEqualityComparer<T>
必须提供两个方法:一个用于比较两个项的相等性(正确地完成)和一个用于获取哈希码(这是做得非常糟糕 - 这是“有效的”,但却极其低效)。基本上,这通过执行比实际需要更多的比较将O(N)算法变为O(N ^ 2)算法。
就单元测试而言,您可以使用我上面给出的几个例子:
您可能希望根据应该返回多个等效项中的哪个项找出需求 - 例如,LINQ to Objects总是返回它遇到的第一个(尽管我不想那是有记录的。)
或者您可以查看我的DistinctByTest
以获取MoreLINQ测试:)