列表.包含奇怪的行为

本文关键字:包含奇 列表 | 更新日期: 2023-09-27 18:25:01

我不知道这里是否遗漏了什么,但奇怪的是,我下面的代码总是在List上引发异常。包含部分,尽管我确信列表包含元素:

using System;
using System.Linq;
using System.Collections.Generic;
class SomeClass
{
  public string param1 {get; private set;}
  public string param2 {get; private set;}
  private SomeClass(){}
  public SomeClass(string param1, string param2)
  {
    this.param1 = param1;
    this.param2 = param2;
  }
}
class SomeClass2
{
  private List<SomeClass> myList = new List<SomeClass>();
  public void Add(SomeClass someclass)
  {
    myList.Add(someclass);
  }
  public void Remove(SomeClass someClass)
  {
    // this part always rises an exception
    if(!myList.Contains(someClass))
      throw new System.ArgumentException("some error");
    else myList.Remove(someClass);
  }
}
class MainClass
{
  public static void Main (string[] args)
  {
    var _someClass = new SomeClass2();          
    _someClass.Add(new SomeClass("aaa", "bbb"));
    try
    {
      _someClass.Remove(new SomeClass("aaa", "bbb"));   
    }
    catch(Exception e)
    {
      Console.WriteLine(e.Message);
    }
  }
}

列表.包含奇怪的行为

引用Contains方法的文档:

此方法通过使用默认相等来确定相等比较器,由对象的IEquatable(Of T)。T的Equals方法(列表中值的类型)。

因此,如果您希望Contains方法确定SomeClass的两个实例是否相等,则可以在对象上实现IEquatable<T>

class SomeClass: IEquatable<SomeClass>
{
    public string param1 { get; private set; }
    public string param2 { get; private set; }
    private SomeClass() { }
    public SomeClass(string param1, string param2)
    {
        this.param1 = param1;
        this.param2 = param2;
    }
    public bool Equals(SomeClass other)
    {
        return param1 == other.param1 && param2 == other.param2;
    }
}

另一种可能性是实现自定义EqualityComparer<T>:

class SomeClassEqualityComparer : IEqualityComparer<SomeClass>
{
    private static readonly SomeClassEqualityComparer _instance = new SomeClassEqualityComparer();
    public bool Equals(SomeClass x, SomeClass y)
    {
        return x.param1 == y.param1 && x.param2 == y.param2;
    }
    public int GetHashCode(SomeClass obj)
    {
        unchecked
        {
            int hash = 17;
            hash = hash * 23 + obj.param1.GetHashCode();
            hash = hash * 23 + obj.param2.GetHashCode();
            return hash;
        }
    }
    public static IEqualityComparer<SomeClass> Instance
    {
        get { return _instance; }
    }
}

然后使用Contains方法的以下重载:

if (!myList.Contains(someClass, SomeClassEqualityComparer.Instance))
    throw new System.ArgumentException("some error");

您没有删除SomeClass的同一个实例。这将起作用:

public static void Main ()
{
    var _someClass = new SomeClass2();
    var someClass = new SomeClass("aaa", "bbb");
    _someClass.Add(someClass);
    try
    {
        _someClass.Remove(someClass); 
    }
    catch(Exception e)
    {
        Console.WriteLine(e.Message);
    }
}

要使您的原始代码正常工作,您需要实现IEquatable。看见http://msdn.microsoft.com/en-us/library/bhkz42b3.aspx.

很抱歉我没有花更多的时间在哈希代码实现上。我甚至不记得^是否是正确的xor运算符。。。我想我可以在xor之前腐烂13,但这似乎有点傻。

using System;
using System.Collections.Generic;
namespace DoesItCompile
{
    class SomeClass
    {
        private object param1;
        private object param2;
        private SomeClass() { }
        public SomeClass(string param1, string param2)
        {
            this.param1 = param1;
            this.param2 = param2;
        }
        public override bool Equals(object oThat)
        {
            if (!(oThat is SomeClass))
                return false;
            SomeClass scThat = (SomeClass)oThat;
            if (!string.Equals(this.param1, scThat.param1))
                return false;
            if (!string.Equals(this.param2, scThat.param2))
                return false;
            return true;
        }
        public override int GetHashCode()
        {
            return this.param1.GetHashCode() ^ this.param2.GetHashCode();
        }
    }
    class SomeClass2
    {
        private List<SomeClass> myList = new List<SomeClass>();
        public void Add(SomeClass someclass)
        {
            myList.Add(someclass);
        }
        public void Remove(SomeClass someClass)
        {
            // this part always rises an exception
            if (!myList.Contains(someClass))
                throw new System.ArgumentException("some error");
            else myList.Remove(someClass);
        }
    }
    class MainClass
    {
        public static void Main(string[] args)
        {
            var _someClass = new SomeClass2();
            _someClass.Add(new SomeClass("aaa", "bbb"));
            try
            {
                _someClass.Remove(new SomeClass("aaa", "bbb"));
                Console.WriteLine("Have a nice president's day.");
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }
            Console.ReadKey();
        }
    }
}

附言-我不知道你为什么要问塞尔达的跟踪者,但我相信有充分的理由。