cdb*_*a89 4 c# generics reflection equality iequalitycomparer
我正在编写实现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();
}
}
Run Code Online (Sandbox Code Playgroud)
我认为这是一个很好的小助手功能,我可以多次使用.
为了使用它,我必须这样做:
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"});
Run Code Online (Sandbox Code Playgroud)
很公平,但我如何处理它返回的obj变量?
someEnumerable.Distinct(obj);
Run Code Online (Sandbox Code Playgroud)
不同扩展函数的重载不接受这个,因为它没有看到IEqualityComparer类型,它当然只看到一个对象.
someEnumerable.Distinct((t) obj);
someEnumerable.Distinct(obj as t);
Run Code Online (Sandbox Code Playgroud)
这也行不通.未找到类型/名称空间(红色下划线).
我如何直截了当?
我将首先为非匿名类型提供解决方案,然后将其扩展为匿名类型.希望它能帮助您理解人们在评论中对您的问题所说的内容.
我的"普遍" 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();
}
}
Run Code Online (Sandbox Code Playgroud)
假设我们首先要使用非匿名类型,例如Person:
public class Person
{
public int Id { get; set; }
public string FirstName { get; set; }
public string Surname { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
用法非常简单:
IEnumerable<Person> people = ... ; // some database call here
var distinctPeople = people.Distinct(new PropertyComparer<Person>("FirstName"));
Run Code Online (Sandbox Code Playgroud)
如您所见,要使用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));
}
}
Run Code Online (Sandbox Code Playgroud)
现在它也可以使用匿名类型:
var distinctPeople = people
.Select(x => new { x.FirstName, x.Surname })
.WithDistinctProperty("FirstName");
Run Code Online (Sandbox Code Playgroud)
突然之间,没有必要指定查询在任何地方处理的确切类型,因为C#编译器足够聪明,可以从上下文中推断出它(在这种情况下,是从上下文中的source参数类型提供的)扩展方法).
希望这会帮助你.
| 归档时间: |
|
| 查看次数: |
5821 次 |
| 最近记录: |