我碰巧看到了一些代码,其中这个人将lambda表达式传递给ArrayList.Sort(IComparer here)或IEnumerable.SequenceEqual(IEnumerable list,IEqualityComparer here),其中需要IComparer或IEqualityComparer。
我不能确定我是否看过它,或者我只是在做梦。我似乎无法在任何接受Func<>的集合中找到扩展名。或其代表签名的代表。
是否有这样的过载/扩展方法?或者,如果没有,是否有可能像这样捣乱并传递一个算法(读委托),其中预期单方法接口?
更新 感谢大家。那正是我所想。我一定是在做梦。我知道如何编写转换。我只是不确定我是否见过这样的东西,或者只是觉得我已经看过了。
又一次更新 看,在这里,我发现了一个这样的例子。毕竟我并没有做梦。看看what this guy is doing here。是什么给了什么?
这是另一个更新:
好的我明白了。这家伙正在使用Comparison<T>
重载。尼斯。很好,但完全容易误导你。不过很好。感谢。
答案 0 :(得分:23)
我也在网上搜索解决方案,但我没有找到任何令人满意的解决方案。所以我创建了一个通用的EqualityComparerFactory:
using System;
using System.Collections.Generic;
/// <summary>
/// Utility class for creating <see cref="IEqualityComparer{T}"/> instances
/// from Lambda expressions.
/// </summary>
public static class EqualityComparerFactory
{
/// <summary>Creates the specified <see cref="IEqualityComparer{T}" />.</summary>
/// <typeparam name="T">The type to compare.</typeparam>
/// <param name="getHashCode">The get hash code delegate.</param>
/// <param name="equals">The equals delegate.</param>
/// <returns>An instance of <see cref="IEqualityComparer{T}" />.</returns>
public static IEqualityComparer<T> Create<T>(
Func<T, int> getHashCode,
Func<T, T, bool> equals)
{
if (getHashCode == null)
{
throw new ArgumentNullException(nameof(getHashCode));
}
if (equals == null)
{
throw new ArgumentNullException(nameof(equals));
}
return new Comparer<T>(getHashCode, equals);
}
private class Comparer<T> : IEqualityComparer<T>
{
private readonly Func<T, int> _getHashCode;
private readonly Func<T, T, bool> _equals;
public Comparer(Func<T, int> getHashCode, Func<T, T, bool> equals)
{
_getHashCode = getHashCode;
_equals = equals;
}
public bool Equals(T x, T y) => _equals(x, y);
public int GetHashCode(T obj) => _getHashCode(obj);
}
}
这个想法是,CreateComparer方法有两个参数:GetHashCode(T)的委托和Equals(T,T)的委托
示例:
class Person
{
public int Id { get; set; }
public string LastName { get; set; }
public string FirstName { get; set; }
}
class Program
{
static void Main(string[] args)
{
var list1 = new List<Person>(new[]{
new Person { Id = 1, FirstName = "Walter", LastName = "White" },
new Person { Id = 2, FirstName = "Jesse", LastName = "Pinkman" },
new Person { Id = 3, FirstName = "Skyler", LastName = "White" },
new Person { Id = 4, FirstName = "Hank", LastName = "Schrader" },
});
var list2 = new List<Person>(new[]{
new Person { Id = 1, FirstName = "Walter", LastName = "White" },
new Person { Id = 4, FirstName = "Hank", LastName = "Schrader" },
});
// We're comparing based on the Id property
var comparer = EqualityComparerFactory.Create<Person>(
a => a.Id.GetHashCode(),
(a, b) => a.Id==b.Id);
var intersection = list1.Intersect(list2, comparer).ToList();
}
}
答案 1 :(得分:22)
我不太确定它到底有什么用处,因为我认为在Base Library中大多数情况下期望IComparer有一个需要比较的重载......但只是为了记录:
在.Net 4.5中,他们添加了一种从比较中获取IComparer的方法: Comparer.Create所以你可以将lambda传递给它并获得IComparer。
答案 2 :(得分:11)
您可以为Array.Sort方法提供lambda,因为它需要一个接受两个T类型对象并返回整数的方法。因此,您可以提供以下定义(a, b) => a.CompareTo(b)
的lambda。下一个整数数组的示例:
int[] array = { 1, 8, 19, 4 };
// descending sort
Array.Sort(array, (a, b) => -1 * a.CompareTo(b));
答案 3 :(得分:5)
public class Comparer2<T, TKey> : IComparer<T>, IEqualityComparer<T>
{
private readonly Expression<Func<T, TKey>> _KeyExpr;
private readonly Func<T, TKey> _CompiledFunc
// Constructor
public Comparer2(Expression<Func<T, TKey>> getKey)
{
_KeyExpr = getKey;
_CompiledFunc = _KeyExpr.Compile();
}
public int Compare(T obj1, T obj2)
{
return Comparer<TKey>.Default.Compare(_CompiledFunc(obj1), _CompiledFunc(obj2));
}
public bool Equals(T obj1, T obj2)
{
return EqualityComparer<TKey>.Default.Equals(_CompiledFunc(obj1), _CompiledFunc(obj2));
}
public int GetHashCode(T obj)
{
return EqualityComparer<TKey>.Default.GetHashCode(_CompiledFunc(obj));
}
}
像这样使用
ArrayList.Sort(new Comparer2<Product, string>(p => p.Name));
答案 4 :(得分:4)
你不能直接传递它,但是你可以通过定义LambdaComparer
除了Func<T,T,int>
之外的类然后在CompareTo
中使用它来实现它。
它不是那么简洁,但你可以通过Func
上的一些创意扩展方法缩短它。
答案 5 :(得分:3)
我为梦想理论投票。
你不能传递一个需要一个对象的函数:System.Delegate的衍生物(这是lambdas是什么)不实现那些接口。
你可能看到的是Converter<TInput, TOutput>
委托的使用,可以用lambda建模。 Array.ConvertAll使用此委托的实例。
答案 6 :(得分:3)
这些方法没有接受委托而不是接口的重载,但是:
Enumerable.OrderBy
Enumerable.Select
Enumerable.SequenceEqual
IEqualityComparer<T>
Func<T, T, bool>
的包装器应该很简单
答案 7 :(得分:1)
如果您需要此函数与lambda以及可能的两种不同元素类型一起使用:
static class IEnumerableExtensions
{
public static bool SequenceEqual<T1, T2>(this IEnumerable<T1> first, IEnumerable<T2> second, Func<T1, T2, bool> comparer)
{
if (first == null)
throw new NullReferenceException("first");
if (second == null)
throw new NullReferenceException("second");
using (IEnumerator<T1> e1 = first.GetEnumerator())
using (IEnumerator<T2> e2 = second.GetEnumerator())
{
while (e1.MoveNext())
{
if (!(e2.MoveNext() && comparer(e1.Current, e2.Current)))
return false;
}
if (e2.MoveNext())
return false;
}
return true;
}
}