Не может сравнить универсальные значения

Я создаю универсальный класс для содержания виджетов, и я испытываю затруднения при реализации, содержит метод:

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'

Если я не могу сравнить типы, как я должен реализовать, содержит? Как делают словари, списки, и все другие универсальные контейнеры делают это??

5
задан Steve H. 10 February 2010 в 16:52
поделиться

6 ответов

У вас есть несколько вариантов

Первый - использовать 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) { }
7
ответ дан 18 December 2019 в 11:56
поделиться
if (b != null)
    if (b.Equals(iteratorB))
        ...
0
ответ дан 18 December 2019 в 11:56
поделиться

Не все объекты реализуют ==, но все будут иметь 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) )
        ...
    }
}
3
ответ дан 18 December 2019 в 11:56
поделиться

Во время компиляции, нет гарантии, что тип в аргументе типа B предоставляет оператор равенства.

Вместо этого вы можете сделать это:

var comparer = EqualityComparer<B>.Default;
foreach (B item in items) {
    if ( comparer.Equals(b, item) ) {
        ....
    }
}
2
ответ дан 18 December 2019 в 11:56
поделиться

Чтобы добавить к ответу Джейсона, вы также можете добавить , где 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 (без ограничений) - это ваш ответ.

3
ответ дан 18 December 2019 в 11:56
поделиться

Если в вашем случае это сойдет вам с рук, тогда все, что потребуется, - это ограничение класса на B

public class WidgetBox<A,B,C> where B : class

, которое устранит проблему

{ {1}}
0
ответ дан 18 December 2019 в 11:56
поделиться
Другие вопросы по тегам:

Похожие вопросы: