Я создаю универсальный класс для содержания виджетов, и я испытываю затруднения при реализации, содержит метод:
public class WidgetBox<A,B,C>
{
public bool ContainsB(B b)
{
// Iterating thru a collection of B's
if( b == iteratorB ) // Compiler error.
...
}
}
Ошибка: Оператор '==' не может быть применен к операндам типа 'V' и 'V'
Если я не могу сравнить типы, как я должен реализовать, содержит? Как делают словари, списки, и все другие универсальные контейнеры делают это??
У вас есть несколько вариантов
Первый - использовать Object.Equals
:
if(b.Equals(iteratorB)) {
// do stuff
}
Будьте осторожны, используя этот вариант; если B
не переопределяет Object.Equals
, то сравнение по умолчанию будет равенством ссылок, когда B
является ссылочным типом, и равенством значений, когда B
является типом значений. Это может быть не то поведение, которое вы ищете, поэтому без дополнительной информации я бы рассмотрел один из следующих двух вариантов.
Второй - добавить ограничение, что B
является IComparable
:
public class WidgetBox<A, B, C> where B : IComparable
так что
if(b.CompareTo(iteratorB) == 0) {
// do stuff
}
Третий - потребовать, чтобы IEqualityComparer
был передан в конструктор WidgetBox
public class WidgetBox<A, B, C> {
IEqualityComparer<B> _comparer;
public WidgetBox(IEqualityComparer<B> comparer) {
_comparer = comparer;
}
// details elided
}
Тогда:
if(_comparer.Equals(b, iteratorB)) {
// do stuff
}
С этим последним вариантом вы можете обеспечить перегрузку, которая по умолчанию будет EqualityComparer
:
public WidgetBox() : this(EqualityComparer<T>.Default) { }
Не все объекты реализуют ==, но все будут иметь Equals (хотя он может быть унаследован от Object.Equals).
public class WidgetBox<A,B,C>
{
public bool ContainsB(B b)
{
// Iterating thru a collection of B's
if( b.Equals(iteratorB) )
...
}
}
Во время компиляции, нет гарантии, что тип в аргументе типа B предоставляет оператор равенства.
Вместо этого вы можете сделать это:
var comparer = EqualityComparer<B>.Default;
foreach (B item in items) {
if ( comparer.Equals(b, item) ) {
....
}
}
Чтобы добавить к ответу Джейсона, вы также можете добавить , где T: IEquatable
, а не IComparable
. Это обеспечивает перегрузку метода Equals
, который принимает параметр T
.
public class WidgetBox<A,B,C> where B : IEquatable<B>
{
public bool ContainsB(B b)
{
// Iterating thru a collection of B's
if( b.Equals(iteratorB) )
...
}
}
Это может быть предпочтительнее простого использования предоставленного метода Object.Equals
, так как он проверяет эквивалентность двух ссылок на объекты (я полагаю) и поэтому может не обеспечить достаточно функциональность, которую вы хотите (например, если вы хотите, чтобы два объекта Person
с одинаковым свойством SSN
считались равными или что-то в этом роде).
Но чтобы ответить на ваш вопрос «как это делают все коллекции .NET», я считаю, что метод Equals
(без ограничений) - это ваш ответ.
Если в вашем случае это сойдет вам с рук, тогда все, что потребуется, - это ограничение класса на B
public class WidgetBox<A,B,C> where B : class
, которое устранит проблему
{ {1}}