List.Contains奇怪的行为

时间:2012-02-19 12:44:46

标签: c# list error-handling

我不知道我是否在这里遗漏了一些东西,但我的代码总是在List.Contains部分引发异常并不奇怪,尽管我确信列表中包含该元素:

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);
    }
  }
}

3 个答案:

答案 0 :(得分:3)

引用Contains方法的documentation

  

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

如果您希望Contains方法确定SomeClass的2个实例是否相等,那么您可以在对象上实现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");

答案 1 :(得分:0)

您没有删除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

答案 2 :(得分:0)

抱歉,我没有花太多时间在哈希码实现上。我甚至不记得^是否是正确的xor运算符...我想我可以在xor之前使用rot13,但这看起来有点傻。

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();
        }
    }
}

P.S。 - 我不知道为什么你带着塞尔达的缠扰者进入这个问题,但我确信这是有充分理由的。