Сбой List.Contains при сравнении объектов
У меня есть класс "Class1", который имеет строковую переменную "sText" в.NET 2.0. Я создал список объектов этого класса "lstClass1". Он сохраняет много объектов этого класса после установки его строковой переменной.
Полный код:
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", даже если он уже присутствует в списке.
Обратите внимание: я не взял простой список строк или строк, потому что я хочу объяснить мою большую проблему со списком, классами и объектами простым способом.
Пожалуйста помоги.
4 ответа
Использование 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();
}
}
Contains будет работать корректно только в том случае, если вы реализуете IEquatable в вашем случае.
Вместо этого вы можете использовать следующий код:
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();
}
Раскомментируйте закомментированные строки, и вы увидите разницу.
Проблема, с которой вы здесь сталкиваетесь, заключается между объектом и экземпляром. Когда вы проверяете следующее, вы в основном спрашиваете "есть ли в коллекции?"
!lstClass1.Contains(new Class1("text1"))
Ну, это, очевидно, не может быть, так как вы только что создали это. Вам нужно проверить содержимое этого объекта. Самый простой способ сделать это - перебрать коллекцию и проверить содержимое каждого объекта.
Это очень легко сделать с помощью LINQ (хотя я не уверен, что он доступен для.NET 2.0):
!lstClass1.Any(i => i.Text == "text1")
Другое решение было бы переписать GetHashCode()
а также Equals
методы вашего Class1, чтобы рассматривать два объекта как "равные", если их содержимое одинаковое. и, таким образом, позволяют провести тщательное сравнение.
Это не удается, потому что список звонков 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;
}