【问题标题】:Setting up a simple iequatable class c#设置一个简单的 iequatable 类 c#
【发布时间】:2016-07-26 08:14:29
【问题描述】:

找不到简单的答案。我的问题是我正在尝试将列表中对象的 VALUE 与对象的 VALUE 进行比较...

我的班级:

public class MatchList 
    {
        public int SomeInt { get; set; }
        public decimal SomeDecimal { get; set; }
    }

我创建了匹配列表。看来我只能比较对象而不是对象的值与 'theMatchList.Contains...'

                            MatchList ML = new MatchList();

                            ML.SomeInt = 12;
                            ML.SomeDecimal = 2.3;
                            if (theMatchlist.Contains(ML))
                            {
                                DoSomething;
                            }

如何触发“DoSomething”?假设“theMatchList”中有一个条目,其值分别等于 12 和 2.3。我知道它与 iequatable 有关,但我不太明白它是如何工作的。提前致谢!

【问题讨论】:

  • 某事后缀List 暗示它包含一个项目列表。但是您的定义似乎只包含 2 个标量值。所以我对你的问题感到困惑 - MatchList 是一个列表吗?它列表中的项目看起来像什么?通常,列表应为IEnumerableIList。您的MatchList 不包含Contains 的定义。您的代码中的theMatchList 是什么?您的问题引发了更多问题。
  • theMatchlistList<MatchList> 类型的吗?

标签: c# list contains


【解决方案1】:

你的命名有点不清楚,我假设你实际上有一个List<MatchList>,你想在其中找到一个特定的MatchList(我建议在这种情况下将MatchList至少重命名为MatchItem,并且更可取的东西更具描述性)。

然后来自List<T>.Contains的文档:

此方法通过使用默认相等比较器来确定相等性,该比较器由对象对 T(列表中值的类型)的 IEquatable<T>.Equals 方法的实现定义。

所以你必须为你的班级实现IEquatable<T>。此外,建议是

[i]如果您实现了 Equals,您还应该重写 Object.Equals(Object) 和 GetHashCode 的基类实现,以便它们的行为与 IEquatable.Equals 方法的行为一致。

如果你实现GetHashCode,它的结果不应该在你的对象的生命周期内改变。在大多数情况下,使类不可变就足够了。如果您需要能够更新字段,则需要以不同的方式实现GetHashCode

总而言之,如果您想使用Contains,您的班级最终会如下所示:

public class MatchList : IEquatable<MatchList>
{
    // Note: Fields are readonly to satisfy GetHashCode contract
    private readonly int someInt;
    private readonly decimal someDecimal;

    // Public constructor creates immutable object
    public MatchList(int myInt, decimal myDecimal)
    {
         this.someInt = myInt;
         this.myDecimal = myDecimal;
    }

    // Properties are now read-only too.
    public int SomeInt { get { return this.someInt; } }
    public decimal SomeDecimal { get { return this.someDecimal; } }

    // Implementation of IEquatable<MatchList>
    public bool Equals( MatchList other )
    {
      return (other != null) 
          && (this.SomeInt == other.SomeInt)
          && (this.SomeDecimal == other.SomeDecimal);
    }

    // Override of Object.Equals
    // Calls the IEquatable.Equals version if possible.
    public override bool Equals( object obj )
    {
        return (obj is MatchList) && this.Equals(obj as MatchList);
    }

    public override int GetHashCode()
    { 
        return (this.someInt * 17) ^ this.someDecimal.GetHashCode();
    }
}

【讨论】:

  • 您应该在Equals( MatchList other ) 中检查null。并且^ (xor) 而不是+ 会产生更好的哈希函数。
  • 感谢@EliArbel,已更新。由于GetHashCode,也使该类不可变。
  • 每次我需要IEquatable 时,工作量都比我想象的要多。
  • ReSharper 让一切变得简单 :)
【解决方案2】:

正如我评论的那样,您的问题还不清楚,所以我会尽力解释这个概念。

您尝试编写的代码很可能是列表中的项目,而不是列表本身:

public class MatchItem : IEquatable<MatchItem>
{
    public int SomeInt { get; set; }
    public decimal SomeDecimal {get; set; }

    public bool Equals(MatchItem item)
    {
        if(item == null)
            return false;

        return this.SomeInt == item.SomeInt && this.SomeDecimal == item.SomeDecimal;
    }

    // You should also override object.ToString, object.Equals & object.GetHashCode. 
    // Omitted for brevity here!
}

您会注意到它有一个IEquatable&lt;MatchItem&gt; 的实现,可以将其与MatchItem 的其他实例进行比较。

此后,此代码将起作用:

var items = new List<MatchItem>()
{
    new MatchItem{SomeInt = 1, SomeDecimal = 0.3M},
    new MatchItem{SomeInt = 12, SomeDecimal = 2.3M}
};

var searchItem = new MatchItem{SomeInt = 1, SomeDecimal = 0.3M};

Console.WriteLine(items.Contains(searchItem)); // true

工作示例:http://rextester.com/ZWNC6890

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-04
    • 2012-05-16
    • 2010-11-20
    • 2012-11-25
    相关资源
    最近更新 更多