C# 优先选择平等比较者<;T>;致IEqualityComparer<;T>;

C# 优先选择平等比较者<;T>;致IEqualityComparer<;T>;,c#,.net,C#,.net,从MSDN的备注部分: 我们建议您从 EqualityComparer类而不是 实现IEqualityComparer 接口,因为 的EqualityComparer类测试 平等使用 IEquatable.Equals方法而不是 Object.Equals方法 我不理解引用的论点,即为什么我们更喜欢从EqualityComparer类派生,而不是实现IEqualityComparer。这意味着实现IEqualityComparer的对象将使用Object.Equals来测试相等性,但当我们不

从MSDN的备注部分:

  • 我们建议您从 EqualityComparer类而不是 实现IEqualityComparer 接口,因为 的EqualityComparer类测试 平等使用 IEquatable.Equals方法而不是 Object.Equals方法

    • 我不理解引用的论点,即为什么我们更喜欢从
      EqualityComparer
      类派生,而不是实现
      IEqualityComparer
      。这意味着实现
      IEqualityComparer
      的对象将使用
      Object.Equals
      来测试相等性,但当我们不想使用
      Object.Equals
      IEquatable.Equals来测试相等性时,实现
      IEqualityComparer
      的目的不是全部吗

    • 它还意味着,如果我们从
      EqualityComparer
      派生,那么派生类将使用
      IEquatable.Equals
      方法测试相等性。同样,当我们不想使用
      Object.Equals
      IEquatable.Equals来测试相等性时,从
      EqualityComparer
      派生的全部要点难道不是吗(因为
      EqualityComparer.Default
      已经使用
      Object.Equals
      IEquatable.Equals

  • 。。。这是符合事实的 包含、IndexOf、LastIndexOf和 删除Dictionary类和其他泛型类的方法 收藏

    • 我通过调用
      IEquatable.Equals
      Object.Equals
      (取决于类型为
      T
      的元素是否实现
      IEquatable
      )通过
      EqualityComparer.Default

    • 为什么这些集合(在测试默认相等性时)不直接调用
      IEquatable.Equals
      Object.Equals
      而不是通过
      EqualityComparer.default


  • 我不明白你给我的建议。我觉得这很奇怪


    至于2,通常情况下,你会得到一个类型(比如
    字典
    )它有一个
    IEqualityComparer
    。虽然实现可以存储一个空值并显式调用
    Equals
    本身,但这样做将是一件痛苦的事情,而且还将涉及到非常丑陋的事情,以确保它不会不必要地将实现
    IEquatable
    的值类型装箱tyComparer.Default
    非常简单且更加一致。

    关于您的第一个问题:

    该类的备注部分似乎并没有真正提供为什么您更喜欢从抽象类派生而不是从接口派生的原因,它听起来更像是一个为什么首先存在equality comparer接口的原因。它所说的实际上是无用的,它基本上描述了默认实现如果有什么区别的话,他们在这里提供的“推理”听起来更像是你的比较器可以做什么的指南,与它实际做什么无关

    查看
    EqualityComparer
    类的公共/受保护接口,只有一个补救性质,它实现了非泛型
    IEqualityComparer
    接口。我认为他们的意思是,他们建议从中派生,因为
    EqualityComparer
    实际上实现了非泛型
    IEqualityComparer
    接口,这样您的类就可以在需要非泛型比较器的地方使用

    在备注一节中,它确实更有意义,因为:

    我们建议您从
    Comparer
    类派生,而不是实现
    IComparer
    接口,因为
    Comparer
    类提供了
    IComparer.Compare
    方法和获取对象默认比较器的
    Default
    属性的显式接口实现。

    我怀疑它应该对
    IEqualityComparer
    说一些类似的话,但有些想法被混淆了,最终导致描述不完整


    关于你的第二个问题:

    在库中找到的集合的一个主要目标是尽可能灵活。实现这一目标的一种方法是,通过提供
    IComparer
    IEqualityComparer
    来进行比较,从而允许自定义方式来比较其中的对象。当一个这些比较器可以包含调用适当的比较所需的逻辑

    e、 例如,默认比较器可以确定
    T
    是否在对象上实现
    IEquatable
    并调用
    IEquatable.Equals
    ,或者使用
    object.Equals
    。在比较器中封装比在集合代码中重复更好

    此外,如果他们想退回到直接调用
    IEquatable.Equals
    ,他们必须在
    T
    上添加一个约束,这将使调用成为可能。这样做会降低灵活性,并否定首先提供比较器的好处

    从基类派生类的主要原因是 类可以提供您可以重用的代码,所以您不必编写它 你自己

    如果要从接口派生比较器,则必须创建 为您自己提供默认比较器的代码(当然,只有在您需要它的情况下,但是大家都想要免费的功能!)

    类使用

    在Factory模式中,我们创建对象而不使用expo
    class DictionaryComparerFactory<TKey, TValue> : 
        EqualitiyComparer<Dictionary<TKey, TValue>>
    {
        // By deriving from EqaulityComparer, you already have comparer (1)
        // via property Default
    
        // comparer (4):
        // X and Y are equal if equal keys and equal values using provided value comparer
        public static IEqualityComparer<Dictionary<TKey, TValue>>
            CreateContentComparer(IEqualityComparer<TValue> valueComparer)
        {
            return new DictionaryComparer<TKey, TValue>(valueComparer);
        }
    
        // comparer (3): X and Y equal if equal keys and values default equal
        // use (4) by providing the default TValue comparer
        public static IEqualityComparer<Dictionary<TKey, TValue>>
            CreateDefaultValueComparer(IEqualityComparer<TValue> valueComparer)
        {
            IEqualityComparer<TValue> defaultValueComparer =
                EqualtiyComparer<TValue>.Default;
            return new DictionaryComparer<TKey, TValue>(defaultValuecomparer);
        }
    
        // comparer (2): X and Y are equal if equal keys and values are same object
        // use reference equal for values
        public IEqualityComparer<TKey, TValue> CreateReferenceValueComparer()
        {
            IEqualityComparer<TValue> referenceValueComparer = ...
            return new DictionaryComparer<TKey, TValue>(referenceValuecomparer);
        }
    }
    
    // constructor
    protected DictionaryComparer(IEqualityComparer<TValue> valueComparer) : base()
    {   // if no comparer provided, use the default comparer
        if (Object.ReferenceEquals(valueComparer, null))
            this.valueComparer = EqualityComparer<TValue>.Default;
        else
            this.valueComparer = valueComparer
    }
    
    // comparer for TValue initialized in constructor
    protected readonly IEqualityComparer<TValue> valueComparer;
    
    public override bool Equals(Dictionary<TKey, TValue> x, Dictionary<TKey, TValue> y)
    {
        if (x == null) { return y == null; } 
        if (y == null) return false;
        if (Object.ReferenceEquals(x, y)) return true;
        if (x.GetType() != y.GetType()) return false;
    
        // now do equality checks according to (4)
        foreach (KeyValuePair<TKey, TValue> xKeyValuePair in x)
        {
            TValue yValue;
            if (y.TryGetValue(xKeyValuePair.Key, out yValue))
            {   // y also has x.Key. Are values equal?
                if (!this.valueComparer.Equals(xKeyValuePair.Value, yValue))
                {   // values are not equal
                    return false;
                }
                // else: values equal, continue with next key
            }
            else
            {   // y misses a key that is in x
                return false;
            }
        }
    
        // if here, all key/values equal
        return true;
    }
    
    var dictionaryX = ...
    var dictionaryY = ...
    
    var valueComparer1 = ...
    var valueComparer2 = ...
    
    var equalityComparer1 = DictionaryComparer<...>.Default();
    var equalityComparer2 = DictionaryComparer<...>..CreateDefaultValueComparer();
    var equalityComparer3 = DictionaryComparer<...>.CreatereferenceValueComparer();
    var equalityComparer4 = DictionaryComparer<...>
       .CreateContentComparer(valueCompaerer1);
    var equalityComparer5 = DictionaryComparer<...>
       .CreateContentComparer(valueCompaerer2);