如何使用IEqualityComparer进行动态比较?

时间:2013-03-04 09:20:17

标签: .net iequalitycomparer

我有一个像这样的人类:

Public Class Person
{
public int Id {get; set;}
public int FirstName {get; set;}
public int LastName {get; set;}
}

我创建了一个Person对象列表:

List<Person> AllPersons = GetAllPersons();

在GetAllPersons()中,我有这段代码,根据Id提供唯一且非重复的人物对象。

        return this.colLoadExternalData.GroupBy(p => p, new MyClass()).Where(g => g.Count() == 1).Select(g => g.Single()).ToList();

如果来源有两个Id = 123的人,则表示列表中没有123。

这是实现IEqualityComparer

的类
public class MyClass : IEqualityComparer<Person>
{
    public bool Equals(Person x, Person y)
    {
        return x.Id == y.Id;
    }

    public int GetHashCode(Person obj)
    {
        return obj.Id.GetHashCode();
    }
}  

MyClass设置基于Id的身份。

我有一个外部配置文件,其中有一个提供设置person类的标识属性的条件,如FirstName或LastName等,它将根据该属性值标识一个唯一的人。

因此,如果配置文件将'FirstName'作为键,那么MyClass将如下所示:

public class MyClass : IEqualityComparer<Person>
{
    public bool Equals(Person x, Person y)
    {
        return x.FirstName == y.FirstName;
    }

    public int GetHashCode(Person obj)
    {
        return obj.FirstName.GetHashCode();
    }
} 

我实际上在向其添加人物对象之前使用了字典,但如果源具有重复的条目,例如两个id为123的人,则仍会添加一个人物对象。 如果可以使用字典对象完成此操作,请确保最终集合确实具有唯一对象,并且不包括来自外部源的重复记录,这将是很好的。

我能做的是在单独的列表中维护一份重复列表。 在该列表上执行一个简单的foreach并从字典中删除这些person对象,如下所示:

foreach(var dup in Duplicates)
{
  UniquePersonObjects.Remove(dup);
}

这里没有使用IEqualityComparer,只需将外部源中的记录添加到字典中,然后根据重复列表进一步过滤该字典。

有更好的方法吗?

问候。

2 个答案:

答案 0 :(得分:1)

我目前找到的最佳实施方法,您可以在following link

找到

public class EqualityComparer:IEqualityComparer { private Func equalsFunction; private Func getHashCodeFunction;

public EqualityComparer(Func<T, T, bool> equalsFunction)
{
    this.equalsFunction = equalsFunction;
}

public EqualityComparer(Func<T, T, bool> equalsFunction, 
    Func<T, int> getHashCodeFunction) : this(equalsFunction)
{
    this.getHashCodeFunction = getHashCodeFunction;
}

public bool Equals(T a, T b)
{
    return equalsFunction(a, b);
}

public int GetHashCode(T obj)
{
    if (getHashCodeFunction == null)
        return obj.GetHashCode();
    return getHashCodeFunction(obj);
}

public EqualityComparer(Func<T, T, bool> equalsFunction) { this.equalsFunction = equalsFunction; } public EqualityComparer(Func<T, T, bool> equalsFunction, Func<T, int> getHashCodeFunction) : this(equalsFunction) { this.getHashCodeFunction = getHashCodeFunction; } public bool Equals(T a, T b) { return equalsFunction(a, b); } public int GetHashCode(T obj) { if (getHashCodeFunction == null) return obj.GetHashCode(); return getHashCodeFunction(obj); }

现在您可以编写自己的过滤方法,例如:

}

答案 1 :(得分:0)

您可以使用MyClass中的配置来处理不同的检查:

public class MyClass : IEqualityComparer<Person>
{
    // here you set the configuration
    private PersonCompareConfiguration personCompareConfiguration;

    public bool Equals(Person x, Person y)
    {
        switch(personCompareConfiguration)
        {
            case CompareId:
                return x.Id == y.Id;
                break;
            case CompareFirstname:
                return x.FirstName == y.FirstName;
                break;
        }
        throw new InvalidArgumentException("personCompareConfiguration cannot be handled");
    }

    public int GetHashCode(Person obj)
    {
        switch(personCompareConfiguration)
        {
            case CompareId:
                return obj.Id.GetHashCode();
                break;
            case CompareFirstname:
                return obj.FirstName.GetHashCode();
                break;
        }
        throw new InvalidArgumentException("personCompareConfiguration cannot be handled");
    }
}

public enum PersonCompareConfiguration
{
    CompareId,
    CompareFirstname
}

另一种(更聪明的)方法是使用MEF导出IEqualityComparer<Person>的实现。请查看this answer,其中介绍了如何导出和导入通用接口。