对于具有多个==运算符重写的类,Null检查是不明确的

本文关键字:检查 不明确 Null 重写 于具 运算符 | 更新日期: 2023-09-27 18:26:40

我有一个类,它有两个==运算符的重写,用于将其与该类的其他实例进行比较,并与字符串的实例进行比较。

class SomeClass
{
    string value;
    public SomeClass (string _Value)
    {
        value = _Value;
    }
    static public bool operator == (SomeClass C1, SomeClass C2)
    {
        return C1.value == C2.value;
    }
    static public bool operator != (SomeClass C1, SomeClass C2)
    {
        return C1.value != C2.value;
    }
    static public bool operator == (SomeClass C1, string C2)
    {
        return C1.value == (string) C2;
    }
    static public bool operator != (SomeClass C1, string C2)
    {
        return C1.value != (string) C2;
    }
}

然而,当我尝试将这个类与null进行比较时:

        Console.WriteLine(someObject == null);

我得到以下错误:

Error CS0121: The call is ambiguous between the following methods or properties: `SomeClass.operator ==(SomeClass, SomeClass)' and `SomeClass.operator ==(SomeClass, string)'

我应该如何定义我的==覆盖,这样我仍然可以空检查这个类的实例?

对于具有多个==运算符重写的类,Null检查是不明确的

由于使用的是null文字,编译器不知道该调用哪个方法,因为stringSomeClass都可以为null。

强制编译器选择其中一种方法的一种技术是对null进行类型转换。

Console.WriteLine(someObject == ((SomeClass)null));

或者更好的是,不要显式使用null,而是使用default关键字来获取null值(因为当T是引用类型时,default(T)是null)。

Console.WriteLine(someObject == default(SomeClass));

您可以在stringSomeClass之间创建隐式转换,而不是定义两个相等运算符:

class SomeClass
{
    string value;
    public SomeClass(string _Value)
    {
        value = _Value;
    }
    static public bool operator ==(SomeClass C1, SomeClass C2)
    {
        return C1.value == C2.value;
    }
    static public bool operator !=(SomeClass C1, SomeClass C2)
    {
        return C1.value != C2.value;
    }
    public static implicit operator string(SomeClass instance)
    {
        return instance.value;
    }
    public static implicit operator SomeClass(string str)
    {
        return new SomeClass(str);
    }
    //TODO override Equals and GetHashCode to use `value`
}

现在,当您将值与null进行比较时,不存在歧义问题。

这也有副作用,使类在其他任何地方都可以隐式地相互转换,但基于上下文,这似乎并不是一件坏事。

您可以将第二个参数作为"对象"传递,并在决定执行哪个等式之前检查其类型。

static public bool operator == (SomeClass C1, object C2)
{
  if(C2 is SomeClass)
    return C1.value == ((SomeClass)C2).value;
  else if (C2 is string)
    return C1.value == (string) C2;
}

对于那些迟到的人,请参阅下面的@Jeppe Stig Nielsen的评论中隐藏的更可接受的答案。

操作人员特别询问了覆盖运算符==的问题,然而,我认为这是覆盖==运算符时的一条重要信息,并认为未来参考的正确答案应该是:-

Console.WriteLine((object)someObject == null);

使用接受的答案并在对象中实现==和Equals,您将继续得到相同的错误。最好在最低级别的对象中与null进行比较,这样您就可以将"object"与null进行对比,并从对比中消除所有歧义。

以下是MSDN中实现的原因和解决方案:重写等于()和运算符==的指南

考虑以下内容,请参阅Equals实现中的注释:-

class SomeClass
{
    string value;
    public SomeClass(string _Value)
    {
        value = _Value;
    }
    static public bool operator ==(SomeClass C1, SomeClass C2)
    {
        return C1.value == C2.value;
    }
    public override bool Equals(SomeClass C1)
    {
        // causes error due to unsure which operator == to use the SomeClass == or the object ==
        // Actual error: Operator '==' is ambiguous on operands of type 'SomeClass' and '<null>'
        if (C1 == null)
            return false;
        // Give same error as above
        if (C1 == default(SomeClass))
            return false;
        // Removes ambiguity and compares using base objects == to null
        if ((object)C1 == null)
            return false;
        return value == C1.value;
    }
}