无法比较通用值

时间:2010-02-10 16:52:21

标签: c# .net generics

我正在创建一个通用类来保存小部件,我在实现contains方法时遇到了麻烦:

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'类型的操作数

如果我无法比较类型,我如何实现包含?字典,列表和所有其他通用容器如何做到这一点?

6 个答案:

答案 0 :(得分:7)

这里有几个选项

第一种是使用Object.Equals

if(b.Equals(iteratorB)) {
    // do stuff
}

小心使用此选项;如果B未覆盖Object.Equals,那么当B是引用类型时,默认比较是引用相等,而B是值类型时,值相等。这可能不是您正在寻求的行为,而且如果没有其他信息,我会考虑接下来的两个选项之一。

第二种是添加BIComparable的约束:

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

这样

if(b.CompareTo(iteratorB) == 0) {
    // do stuff
}

第三个是要求IEqualityComparer<B>传递给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<T>.Default的重载:

public WidgetBox() : this(EqualityComparer<T>.Default) { }

答案 1 :(得分:3)

并非所有对象都实现==但所有对象都具有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) )
        ...
    }
}

答案 2 :(得分:3)

要添加到Jason的答案,您还可以添加where T : IEquatable<T>而不是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 :(得分:2)

在编译时,无法保证类型参数B中的类型提供相等运算符。

相反,你可以这样做:

var comparer = EqualityComparer<B>.Default;
foreach (B item in items) {
    if ( comparer.Equals(b, item) ) {
        ....
    }
}

答案 4 :(得分:0)

if (b != null)
    if (b.Equals(iteratorB))
        ...

答案 5 :(得分:0)

如果你可以在你的情况下侥幸逃脱,那么所需要的只是B

上的一个类约束
public class WidgetBox<A,B,C> where B : class

将消除问题