实现的IEqualityComparer< T>任何类的比较的任意属性(包括匿名) [英] Implementing IEqualityComparer<T> for comparing arbitrary properties of any class (including anonymous)

查看:195
本文介绍了实现的IEqualityComparer< T>任何类的比较的任意属性(包括匿名)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我写这整齐类实现的IEqualityComparer,这样我就可以通过任何匿名类型(或者实际上任何类型的属性),它会通过比较类型的属性值自动比较的类型。

I am writing this neat class implementing IEqualityComparer, so that I can just pass any anonymous type to it (or actually any type with properties) and it will automatically compare the types by comparing the property values of the types.

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();
        }
    }



我认为这是一个不错的辅助函数我可以。多次使用

I thought this was a nice little helper function I could use many times.

为了使用这个,我要做的:

In order to use this, I have to do:

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变量返回?

Fair enough, but what do I do with the obj variable it returns?

someEnumerable.Distinct(obj);



在不同的扩展函数的重载不接受这一点,因为它没有看到的IEqualityComparer类型, 。它只关注过程的一个对象,

The overload of the distinct extension function does not accept this, because it does not see a IEqualityComparer type, it only sees an object, of course.

someEnumerable.Distinct((t) obj);
someEnumerable.Distinct(obj as t);

这也不起作用。类型/命名空间未找到(红色下划线)。

This also doesn't work. Type/Namespace not found (red underline).

我如何得到这个直?

推荐答案

我将首先提供非匿名类型的解决方案,后来它扩大到匿名类型的正常工作。我们希望,它会帮助你了解什么人试图评论你的问题说了。

I'll first provide a solution for non-anonymous types and afterwards extend it to work for anonymous types as well. Hopefully, it will help you to understand what people were trying to say in comments to your question.

我的万能的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();
    }
}



说,我们要与非匿名使用头型,如

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 从自己的上下文。整洁的方式做,这是写在下面的扩展方法:

As you can see, to use the PropertyComparer<T>, we need to specify the type (the T) instances of which are going to be compared against each other. What would the T be when dealing with anonymous types? Since they are generated at runtime, you cannot use the comparer by directly creating its instance, simply because you do not know the T at compile time. Instead, you need to use type-inference to let the C# compiler infer T from context on its own. Neat way to do this is to write the following extension method:

public static class LinqExtensions
{
    public static IEnumerable<T> WithDistinctProperty<T>(this IEnumerable<T> source, string propertyName)
    {
        return source.Distinct(new PropertyComparer<T>(propertyName));
    }
}

现在它也将与匿名类型工作:

Now it will also work with anonymous types:

var distinctPeople = people
        .Select(x => new { x.FirstName, x.Surname })
        .WithDistinctProperty("FirstName");



突然,没有必要指定查询处理任何地方的确切类型,因为C#编译器是足够聪明,从上下文(在这种情况下,正在从源的扩展方法参数的类型提供)来推断。

All of a sudden, there is no need to specify the exact type the query is dealing with anywhere, since C# compiler is smart enough to infer it from the context (which, in this case, is being provided from the type of source parameter in the extension method).

希望这会帮助你。

这篇关于实现的IEqualityComparer&LT; T&GT;任何类的比较的任意属性(包括匿名)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆