如何使用IEqualityComparer

Akr*_*rem 90 c# linq iequalitycomparer

我的数据库中有一些相同数字的铃声.我希望所有这些都没有重复.然后我创建了一个比较类来完成这项工作,但是函数的执行从函数中产生了很大的延迟而没有明显的,从0.6秒到3.2秒!

我做得对吗还是我必须使用其他方法?

reg.AddRange(
    (from a in this.dataContext.reglements
     join b in this.dataContext.Clients on a.Id_client equals b.Id
     where a.date_v <= datefin && a.date_v >= datedeb
     where a.Id_client == b.Id
     orderby a.date_v descending 
     select new Class_reglement
     {
         nom  = b.Nom,
         code = b.code,
         Numf = a.Numf,
     })
    .AsEnumerable()
    .Distinct(new Compare())
    .ToList());

class Compare : IEqualityComparer<Class_reglement>
{
    public bool Equals(Class_reglement x, Class_reglement y)
    {
        if (x.Numf == y.Numf)
        {
            return true;
        }
        else { return false; }
    }
    public int GetHashCode(Class_reglement codeh)
    {
        return 0;
    }
}
Run Code Online (Sandbox Code Playgroud)

Kon*_*lph 165

难怪,考虑到你的GetHashCode实现总是返回相同的值.Distinct依靠良好的哈希函数来高效工作.

当实现的类接口,你需要阅读的文件第一次,否则你不知道你应该执行哪一项合同.1

在你的代码,解决办法是转发GetHashCodeClass_reglement.Numf.GetHashCode并实施适当的存在.

除此之外,您的Equals方法充满了不必要的代码.它可以重写如下(相同的语义,¼代码,更可读):

public bool Equals(Class_reglement x, Class_reglement y)
{
    return x.Numf == y.Numf;
}
Run Code Online (Sandbox Code Playgroud)

此外,ToList呼叫是不必要和耗时的:AddRange接受任何调用,因此不需要IEnumerable转换为a List.AsEnumerable这里多余的,因为处理结果AddRange无论如何都会导致此.


1实现代码而不知道它实际上做了什么称为货物崇拜编程.这是一种令人惊讶的普遍做法.它从根本上说是行不通的.

  • 哇.*憎恶*不必要地苛刻.我们在这里互相帮助,而不是侮辱.我想这会让一些人发笑,但我建议删除它. (43认同)
  • 当x或y为空时,等于失败. (17认同)
  • @dzendras对于`GetHashCode`也是如此.但请注意,[IEqualityComparer <T>`](http://msdn.microsoft.com/en-us/library/ms132151.aspx)的文档没有说明如何处理`null`参数 - 但是文章中提供的示例也不处理`null`. (4认同)
  • +1让我在wiki上阅读"货物崇拜编程",然后将我的skype标记行改为"//深魔术从这里开始......然后是一些沉重的魔法". (4认同)
  • @dzendras使用C#6空条件https://msdn.microsoft.com/zh-cn/library/dn986595.aspx,他可以执行return x?.Numf == y?.Numf;` (2认同)
  • 判断某人的代码令人厌恶并假设他们不了解他们在做什么,这有点苛刻 - 没有人可以知道一切。您还可以指出问题 /sf/ask/25992991/ 以帮助解释更多 (2认同)
  • “在实现类的接口时,您需要先阅读它们的文档”和“在不知道实际内容的情况下实现代码 &lt;snip&gt; 不起作用。” - 这家伙不需要他寻求帮助的讲座。并不是每个人都像您认为的那样擅长计算机编程! (2认同)
  • @NeilBenn你错误坦率的建议是粗鲁的.由于OP接受了答案(而且,我可能会注意到,在更严格的版本中!),他们似乎没有犯同样的错误.我不确定你为什么认为提供建议是粗鲁的,但当你说"那个人不需要讲课"时你就错了.我非常不同意:讲座*是*需要的,并且它被铭记于心.编写的代码很糟糕,并且基于糟糕的工作实践.没有指出这将是一种伤害,并没有任何帮助,因为那时OP无法改善他们的工作方式. (2认同)

小智 46

试试这段代码:

public class GenericCompare<T> : IEqualityComparer<T> where T : class
{
    private Func<T, object> _expr { get; set; }
    public GenericCompare(Func<T, object> expr)
    {
        this._expr = expr;
    }
    public bool Equals(T x, T y)
    {
        var first = _expr.Invoke(x);
        var sec = _expr.Invoke(y);
        if (first != null && first.Equals(sec))
            return true;
        else
            return false;
    }
    public int GetHashCode(T obj)
    {
        return obj.GetHashCode();
    }
}
Run Code Online (Sandbox Code Playgroud)

它的使用范例是

collection = collection
    .Except(ExistedDataEles, new GenericCompare<DataEle>(x=>x.Id))
    .ToList(); 
Run Code Online (Sandbox Code Playgroud)

  • `GetHashCode`也需要使用表达式:`return _expr.Invoke(obj).G​​etHashCode();`参见[this post](http://stackoverflow.com/q/25513372/450913)了解它的用法. (19认同)

use*_*754 5

如果您想要一个通用解决方案,根据该类的属性(充当键)为您的类创建一个 IEqualityComparer,请查看以下内容:

public class KeyBasedEqualityComparer<T, TKey> : IEqualityComparer<T>
{
    private readonly Func<T, TKey> _keyGetter;

    public KeyBasedEqualityComparer(Func<T, TKey> keyGetter)
    {
        if (default(T) == null)
        {
            _keyGetter = (x) => x == null ? default : keyGetter(x);
        }
        else
        {
            _keyGetter = keyGetter;
        }
    }

    public bool Equals(T x, T y)
    {
        return EqualityComparer<TKey>.Default.Equals(_keyGetter(x), _keyGetter(y));
    }

    public int GetHashCode(T obj)
    {
        TKey key = _keyGetter(obj);

        return key == null ? 0 : key.GetHashCode();
    }
}

public static class KeyBasedEqualityComparer<T>
{
    public static KeyBasedEqualityComparer<T, TKey> Create<TKey>(Func<T, TKey> keyGetter)
    {
        return new KeyBasedEqualityComparer<T, TKey>(keyGetter);
    }
}
Run Code Online (Sandbox Code Playgroud)

为了获得更好的结构性能,没有任何装箱。

用法是这样的:

IEqualityComparer<Class_reglement> equalityComparer =
  KeyBasedEqualityComparer<Class_reglement>.Create(x => x.Numf);
Run Code Online (Sandbox Code Playgroud)