【问题标题】:C# List<Object>.Equals fails on object comparisonC# List<Object>.Equals 对象比较失败
【发布时间】:2019-03-13 02:15:53
【问题描述】:

我有一个如下的课程。对于此类的对象,我需要添加一种新语言以防它不存在

using System;
using System.Collections.Generic;
namespace discovery.POCO
{
    public class MultiLingualObject 
    {
        public string TableName { get; set; }
        public string BranchId { get; set; }
        public int    GenericId { get; set; }
        public string GenericCode { get; set; }
        public List<MultiLingualColumn> MultiLingColumnsCollection = new List<MultiLingualColumn>();
    }
    public class MultiLingualColumn : IEquatable<MultiLingualColumn>
    {
        public string ColumnName { get; set; }
        public string LanguageCode { get; set; }
        public string LanguageText { get; set; }

        public bool Equals(MultiLingualColumn other)
        {
            if (other == null) return false;
            return  string.Equals(ColumnName,other.ColumnName) &&
                    string.Equals(LanguageCode, other.LanguageCode) &&
                    string.Equals(LanguageText, other.LanguageText);
        }
        public override bool Equals(object obj)
        {
            if (ReferenceEquals(null, obj)) return false;
            if (ReferenceEquals(this, obj)) return true;
            if (obj.GetType() != GetType()) return false;
            return Equals(obj as MultiLingualColumn);
        }
    }

}

由于我是 C# 新手,所以我搜索了各种解决方案,包括 .ContainsEqual(我在上面的 Equal 中添加了覆盖)。我也知道我可以通过简单地使用where like this 来实现比较。然而,由于我可能会在类中添加更多元素,因此如果可能的话,我想坚持使用 Equal 或 Contains。我用来比较然后在不存在时插入的代码如下

internal void UpdateLocalMultiLing()
        {
            POCO.MultiLingualColumn _equals = new POCO.MultiLingualColumn()
            {
                ColumnName = InvoiceComment.Name.TrimEnd(),
                LanguageCode = inputLanguage,
                LanguageText = InvoiceComment.Value.TrimEnd()
            };

            if (!SupplierMultiLing.MultiLingColumnsCollection.Equals(_equals))
                SupplierMultiLing.MultiLingColumnsCollection.Add(new POCO.MultiLingualColumn
                {
                    ColumnName   = InvoiceComment.Name.Trim(),
                    LanguageCode = inputLanguage,
                    LanguageText = InvoiceComment.Value.Trim()
                }
                );
        }

但它会忽略条件并再次添加相同的语言。从附图可以看出。

请告诉我应该解决什么问题?

【问题讨论】:

标签: c# .net list object equals-operator


【解决方案1】:

您正在将列表与单个对象进行比较。您需要.Contains() 而不是.Equals()

要么正确实现IEquatable&lt;T&gt;,要么正确实现override Equals(object) and GetHashCode()。来自What does Collection.Contains() use to check for existing objects?

要么在你的自定义类上实现 IEquatable,要么覆盖 Equals(和 GetHashCode)

此代码打印“True”:

public class Foo : IEquatable<Foo>
{
    public string Bar { get; set; }

    public bool Equals(Foo other)
    {
        return other.Bar == this.Bar;
    }
}

public static void Main()
{
    var list = new List<Foo>
    {
        new Foo { Bar = "Baz" }
    };

    Console.WriteLine(list.Contains(new Foo { Bar = "Baz" }));
}

但由于@Jeppe 正确地进行了匹配,建议还为其他收集和比较类型提供GetHashCode() 的正确实现。

【讨论】:

  • 仅供参考 - 关于您对 GetHashCode() 的评论,您的链接明确表示他需要 IEquatableGetHashCode() 并且 OP 使用了 IEquatable - 所以他不需要它...迟到……
  • @RandRandom 如果你实现IEquatable&lt;&gt; 和/或覆盖Equals(object),不覆盖GetHashCode是一个非常糟糕的主意。没有它,它对于List&lt;&gt;.Contains 来说已经足够好了。但是一旦你使用Dictionary&lt;,&gt;HashSet&lt;&gt;,或者像Linq 的.Distinct() 之类的东西,它就会失败。至少,包括public override int GetHashCode() =&gt; throw new NotSupportedException(); 以防止在脚上开枪。
  • @JeppeStigNielsen 这可能是新手的问题,但是重写 GetHashCode 会对性能产生影响吗?
  • @KDWolf 是的,如果你覆盖 GetHashCode() 并且你曾经使用过任何可以利用 GetHashCode() 的功能,就像我在第一条评论中提到的那样,那么精确的实现可能会影响表现。但首要任务应该是正确的行为。如果你不覆盖,你会得到不正确的行为。例如,如果您使用list.Distinct().Count(),并且您在List&lt;&gt; 中有两个或更多“相等”但不“相同”的实例,那么如果您不覆盖GetHashCode(),您几乎肯定会得到错误的计数。
  • @RandRandom 是的。当然,使用显式 IEqualityComparer&lt;&gt; 只是将“问题”移动到该类。如果您不想尝试编写GetHashCode()GetHashCode(obj) 的良好实现,您可以: (A) 直接抛出NotSupportedException,这意味着一旦需要GetHashCode,您就会被告知。或者,(B) 只返回一个常量,例如您的 -1,这将提供正确的行为,但性能。哪一个都好。永远不要使用来自System.Object 的未被覆盖的GetHashCode,因为您稍后会遇到“难以理解”的问题。
【解决方案2】:

您应该使用Contains() 方法。您还应该为MultiLingualColumn 实现IEquatable 接口或实现IEqualityComparer 并将第二个参数传递给Contains()。我更喜欢第二种选择:

public class MultiLingualColumnComparer : IEqualityComparer<MultiLingualColumn>
{
    public bool Equals(MultiLingualColumn x, MultiLingualColumn y)
    {
        //...
    }

    public int GetHashCode(MultiLingualColumn obj)
    {
        //...
    }
}

然后:

if (!SupplierMultiLing.MultiLingColumnsCollection.Contains(_equals, new MultiLingualColumnComparer()))

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-02-16
    • 2017-09-07
    • 1970-01-01
    • 2016-02-01
    • 2020-05-28
    • 1970-01-01
    • 2015-11-16
    相关资源
    最近更新 更多