【问题标题】:SequenceEqual different resultsSequenceEqual 不同的结果
【发布时间】:2017-03-13 14:36:01
【问题描述】:

在下面的代码中,当使用类泛型类型定义 List(调用EquatableClass.Equals<>)时,在泛型列表上调用 SequenceEqual 返回 true(如预期的那样)。

如果 list 使用IEquatable 接口定义,则不会调用 Equals 方法并且结果为 false(而是调用 object.Equals,而不是在代码中)。

问题是,为什么第二种情况没有调用EquatableClass.Equals<>方法?

public class EquatableClass : IEquatable<EquatableClass>
{
        public string Name { get; set; }
        public bool Equals(EquatableClass other) => this.Name.Equals(other.Name);        
}

static void Main(string[] args)
{
    var A = new List<EquatableClass> {  new EquatableClass { Name = "A" } };
    var B = new List<EquatableClass> {  new EquatableClass { Name = "A" } };

    var result1 = A.SequenceEqual(B); // == true;

    var AA = new List<IEquatable<EquatableClass>> {  new EquatableClass { Name = "A" } };
    var BB = new List<IEquatable<EquatableClass>> {  new EquatableClass { Name = "A" } };

    var result2 = AA.SequenceEqual(BB); // == false;    
}

【问题讨论】:

  • 因为参数与类参数不匹配。所以使用默认方法。
  • 这就是如果你正在实现IEquatable&lt;T&gt;你应该覆盖Equals(object)的行为以匹配行为的原因。
  • 总是覆盖Equals(+ GetHashCode),例如:public override bool Equals(object obj) { EquatableClass other = obj as EquatableClass; return obj != null &amp;&amp; other.Equals(this); }

标签: c# iequatable


【解决方案1】:

SequenceEqual&lt;T&gt; 方法将尝试查看它是否可以将T 转换为IEquatable&lt;T&gt;,如果可以,它将使用IEquatable&lt;T&gt;.Equals 进行相等。

当您有List&lt;EquatableClass&gt; 时,它会尝试将EquatableClass 转换为IEquatable&lt;EquatableClass&gt;,并且成功,因此它使用适当的Equals 方法。

当你有一个List&lt;IEquatable&lt;EquatableClass&gt;&gt; 时,它会尝试将IEquatable&lt;EquatableClass&gt; 转换为IEquatable&lt;IEquatable&lt;EquatableClass&gt;&gt;,这会失败,因为实际的对象没有实现IEquatable&lt;IEquatable&lt;EquatableClass&gt;&gt;,所以它采用了使用的默认行为object.Equals(object),你不要覆盖它。

【讨论】:

  • 好吧,据我了解,可以简化为:typeof(IEquatable&lt;IEquatable&lt;EquatableClass&gt;&gt;).IsAssignableFrom(typeof(EquatableClass)) == false,原因是IEquatable接口泛型参数被声明为invariant,对吗?
  • @user4662448 如果IEquatable 是协变的或逆变的,则不会有任何不同。该转换不适用于该类型的任何情况。它需要实际实现IEquatable&lt;IEquatable&lt;EquatableClass&gt;&gt; 并添加额外的Equals 方法才能工作。 (这显然不是一个好主意)。
  • 但是添加额外的Equals 不起作用,而是调用 object.Equals...
  • @user4662448 如果您添加第二个IEquatable 实现,它将被使用。你不想那样做。错误是您在不应该的情况下将列表键入为IEquatable。正确的解决方案是使用您实际能够比较的类型列表,这是 EquatableClass 而不是 IEquatable&lt;EquatableClass&gt;&gt;,但如果您添加额外的 IEquatable 实现,您至少会看到发生了什么,尽管您不应该将其保留在代码中。
  • Servy,你写了关于额外的IEquatable&lt;IEquatable&lt;EquatableClass&gt;&gt; 实现,对吧?但是当我将实现添加到EquatableClass 中时,不会调用Equals(IEquatable&lt;EquatableClass&gt; other) 方法。为什么? (我个人的看法是它与 IEquatable 的不变性有某种关系......但我可能错了)。
猜你喜欢
  • 1970-01-01
  • 2015-01-19
  • 2014-12-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多