Ответ
Сравнение ссылочных типов в C# зависит от используемого оператора или метода. По умолчанию сравнение идет по ссылке (адресу в памяти), но это поведение можно переопределить для сравнения по значению.
1. Сравнение по ссылке (Reference Equality)
- Оператор
==: Для большинства ссылочных типов (кромеstring) сравнивает, указывают ли две переменные на один и тот же объект в куче. - Статический метод
object.ReferenceEquals(a, b): Явно сравнивает ссылки.
var obj1 = new object();
var obj2 = new object();
var obj3 = obj1;
Console.WriteLine(obj1 == obj2); // False (разные объекты)
Console.WriteLine(obj1 == obj3); // True (одна и та же ссылка)
Console.WriteLine(ReferenceEquals(obj1, obj2)); // False
2. Сравнение по значению (Value Equality)
Для его реализации необходимо переопределить виртуальные методы object.Equals(object) и object.GetHashCode(), а также часто реализуют интерфейс IEquatable<T> для типобезопасного и эффективного сравнения.
public class Person : IEquatable<Person>
{
public string Name { get; set; }
public bool Equals(Person other)
{
if (other is null) return false;
return Name == other.Name;
}
public override bool Equals(object obj) => Equals(obj as Person);
public override int GetHashCode() => Name?.GetHashCode() ?? 0;
}
// Использование
var person1 = new Person { Name = "Alice" };
var person2 = new Person { Name = "Alice" };
Console.WriteLine(person1 == person2); // False (по-прежнему сравнение ссылок, если не перегружен оператор ==)
Console.WriteLine(person1.Equals(person2)); // True (используется наша логика сравнения по значению)
3. Особый случай: string
Класс string является ссылочным типом, но операторы == и != в C# для него перегружены для сравнения значений, а не ссылок. Это поведение задано на уровне языка.
Рекомендация: Для универсального и безопасного сравнения значений используйте EqualityComparer<T>.Default.Equals(a, b). Этот метод автоматически использует корректную логику сравнения: IEquatable<T>, переопределенный Equals или сравнение ссылок.