2014-02-07 35 views
5

我有一个在.NET 2.0中有一个字符串变量“sText”的类“Class1”。我创建了该类“lstClass1”的对象列表。它在设置字符串变量后存储该类的许多对象。List.Contains在对象比较上失败

完整代码:

public partial class Form1 : Form 
{ 
    public Form1() 
    { 
     InitializeComponent(); 
    } 

    private void button1_Click(object sender, EventArgs e) 
    { 
     if (!lstClass1.Contains(new Class1("text1"))) 
      lstClass1.Add(new Class1("text1")); 
    } 

    public List<Class1> lstClass1 = new List<Class1>(); 
} 

public class Class1 
{ 
    public Class1(string sText) 
    { 
     this.sText = sText; 
    } 

    public string sText = ""; 
} 

现在的问题是,我只想补充一点,有串具有独特的文本值类对象。例如,如果lstClass1已经有一个包含字符串变量值“text1”的对象,那么它不应该允许添加也包含“text1”的对象。所以,我写代码:

if (!lstClass1.Contains(new Class1("text1"))) 
    lstClass1.Add(new Class1("text1")); 

但它总是让即使已存在与“text1”中的字符串列表中的一个对象添加文本“text1”中。我的假设是,在第一次按钮点击事件“button1_Click”时,对象将被添加,因为列表是空的,但在下一个按钮时点击List.Contains函数将检查列表中是否已经有字符串变量“text1”的对象,并且如果找到,则不会被添加。但它始终允许添加带有文本“text1”的对象,即使它已经存在于列表中。

请注意:我没有采取简单的字符串或字符串列表,因为我想用简单的方式解释列表,类和对象的大问题。

请帮忙。

+1

您是否提供了Class1的默认Equals和GetHashCode方法的实现? – Oscar

+0

http://stackoverflow.com/questions/10454519/best-way-to-compare-two-complex-object – k06a

+0

不知道你为什么不把这个'新的Class1(“text1”)'存储到一个新的'Class1 '-type变量,顺便说一句。没有必要两次构建它。只需构造一次,在变量上检查它,然后从变量中存储它。 – Nyerguds

回答

7

使用Any()方法:

if (!lstClass1.Any(x => x.sText == "text1")) 
    lstClass1.Add(new Class1("text1")); 

此代码:

if (!lstClass1.Contains(new Class1("text1"))) 
    lstClass1.Add(new Class1("text1")); 

只能工作,如果你将提供Equals()GetHashCode()方法为您Class1,使制作的这两个对象之间的比较类。要达到此目的,您的班级应实施IEquatable界面。 所以你的Class1看起来是这样的:

public class Class1 : IEquatable<Class1> 
{ 
    public Class1(string sText) 
    { 
     this.sText = sText; 
    } 

    public string sText = ""; 

    public bool Equals(Class1 other) 
    { 
     if (other == null) 
     return false; 

     if (this.sText == other.sText) 
     return true; 
     else 
     return false; 
    } 

    public override int GetHashCode() 
    { 
     return this.sText.GetHashCode(); 
    } 
} 
0

失败的原因是名单上的实例调用Equals,以及默认的实现确实为参考平等检查。尽管你的对象具有name属性值,但它是一个不同的实例,所以引用不会相同。

Class1覆盖的Equals方法来比较的基本性质

public override bool Equals(object other) 
{ 
    Class1 rhs=other as Class1; 
    if(rhs==null) return false; 

    return this.sText == rhs.sText; 
} 
0

你面对这里的问题是对象和背景之间。当你检查以下内容时,你基本上要求“在收藏中?”

!lstClass1.Contains(new Class1("text1")) 

那么它显然不能,因为你刚才创建它。你需要检查的是该对象的内容。最简单的方法是遍历集合并检查每个对象的内容。

这对于LINQ来说很简单(尽管我不确定它是否适用于.NET 2。0):

!lstClass1.Any(i => i.Text == "text1") 

另一种解决办法是覆盖你的Class1的GetHashCode()Equals方法来考虑两个对象作为“等于”,如果它们的内容是相同的。从而可以进行彻底的比较。

1

只有在您的情况下实现IEquatable时,Contains才会正常工作。

您可以使用下面的代码来代替:

public class Class1 //: IEquatable<Class1> 
{ 
    public string sText = ""; 
    public Class1(string sText) 
    { 
     this.sText = sText; 
    } 

    //public bool Equals(Class1 other) 
    //{ 
    // return this.sText == other.sText; 
    //} 
} 
static void Main(string[] args) 
{ 
    List<Class1> lstClass1 = new List<Class1>() { new Class1("text1") }; 
    if (!lstClass1.Contains(new Class1("text1"))) 
     lstClass1.Add(new Class1("text1")); 
    Console.WriteLine(lstClass1.Count); 
    Console.ReadKey(); 
} 

取消对注释行,你会看到其中的差别。