我写这整齐类实现的IEqualityComparer,这样我就可以通过任何匿名类型给它(或者实际上任何类型的属性),它会通过比较类型的属性值自动比较的类型。
public class CompareProperty<T> : IEqualityComparer<T>
{
private Type type;
private PropertyInfo propInfo;
private string _fieldName;
public string fieldName
{
get;
set;
}
public CompareProperty(string fieldName)
{
this.fieldName = fieldName;
}
public bool Equals<T>(T x, T y)
{
if (this.type == null)
{
type = x.GetType();
propInfo = type.GetProperty(fieldName);
}
object objX = propInfo.GetValue(x, null);
object objY = propInfo.GetValue(y, null);
return objX.ToString() == objY.ToString();
}
}
我认为这是一个可爱的小助手功能,我可以用很多次。
为了利用这一点,我必须这样做:
var t = typeof(CompareProperty<>);
var g = t.MakeGenericType(infoType.GetType());
var c = g.GetConstructor(new Type[] {String.Empty.GetType()});
var obj = c.Invoke(new object[] {"somePropertyName"});
不够公平,但我该怎么做,它返回obj变量?
someEnumerable.Distinct(obj);
在不同的扩展功能的过载不接受这一点,因为它没有看到的IEqualityComparer类型,只看到一个对象,当然。
someEnumerable.Distinct((t) obj);
someEnumerable.Distinct(obj as t);
这也不起作用。 类型/命名空间未找到(红色下划线)。
我如何得到这个直?
我将首先提供非匿名类型的解决方案,后来它扩大到匿名类型的正常工作。 我们希望,它会帮助你了解什么人试图在评论你的问题说了。
我的“万能” IEqualityComparer<>
是这样的:
public class PropertyComparer<T> : IEqualityComparer<T>
{
private readonly PropertyInfo propertyToCompare;
public PropertyComparer(string propertyName)
{
propertyToCompare = typeof(T).GetProperty(propertyName);
}
public bool Equals(T x, T y)
{
object xValue = propertyToCompare.GetValue(x, null);
object yValue = propertyToCompare.GetValue(y, null);
return xValue.Equals(yValue);
}
public int GetHashCode(T obj)
{
object objValue = propertyToCompare.GetValue(obj, null);
return objValue.GetHashCode();
}
}
说,我们希望首先与非匿名类型使用它,就像Person
:
public class Person
{
public int Id { get; set; }
public string FirstName { get; set; }
public string Surname { get; set; }
}
用法将是相当简单:
IEnumerable<Person> people = ... ; // some database call here
var distinctPeople = people.Distinct(new PropertyComparer<Person>("FirstName"));
正如可以看到,使用PropertyComparer<T>
我们需要指定类型( T
其中打算)实例针对彼此进行比较。 将在什么T
匿名类型打交道呢? 由于它们在运行时产生的,你不能直接创建它的实例,仅仅是因为你不知道用比较器T
在编译时。 相反,你需要使用类型推断 ,让C#编译器推断T
从自己的上下文。 整洁的方式做,这是写在下面的扩展方法:
public static class LinqExtensions
{
public static IEnumerable<T> WithDistinctProperty<T>(this IEnumerable<T> source, string propertyName)
{
return source.Distinct(new PropertyComparer<T>(propertyName));
}
}
现在,它也将与匿名类型的工作:
var distinctPeople = people
.Select(x => new { x.FirstName, x.Surname })
.WithDistinctProperty("FirstName");
突然,没有必要指定查询处理任何地方的确切类型,因为C#编译器是足够聪明,从上下文(在这种情况下,正在从类型提供推断出它source
参数扩展方法)。
希望这会帮助你。
只需添加自己的验证。
class PropertyComparer<T, TResult> : IEqualityComparer<T>
{
private Func<T, TResult> _getProperty;
public PropertyComparer(Func<T, TResult> predicate)
{
this._getProperty = predicate;
}
public bool Equals(T x, T y)
{
return this._getProperty(x).Equals(_getProperty(y));
}
public int GetHashCode(T obj)
{
return this._getProperty(obj).GetHashCode();
}
}
类与扩展方法:
public static class IEnumerableExtensions
{
public static IEnumerable<TSource> DistinctBy<TSource, TResult>
(this IEnumerable<TSource> source, Func<TSource, TResult> predicate)
{
return source.Distinct(new PropertyComparer<TSource, TResult>(predicate));
}
}
用法:
someEnumerable.DistinctBy(i => i.SomeProperty);