Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Null checking is ambiguous for a class with several overrides for == operator

I have a class with two overrides for == operator, to compare it to other instances of this class, and to compare to instance of string.

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;
    }
}

However, when I try to compare this class to null:

        Console.WriteLine(someObject == null);

I get the following error:

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

How should I define my == overrides so I can still null-check instances of this class?

like image 786
Max Yankov Avatar asked Aug 05 '13 17:08

Max Yankov


3 Answers

Since you're using a null literal, the compiler doesn't know which method to call since both string and SomeClass can be null.

One technique to force the compiler to choose one of the methods is to typecast the null.

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

Or better yet, instead of using null explicitly, use the default keyword to get the null value (because default(T) is null when T is a reference type).

Console.WriteLine(someObject == default(SomeClass));
like image 163
voithos Avatar answered Nov 12 '22 07:11

voithos


Rather than defining two equality operators, you could create an implicit conversion between string and SomeClass:

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`
}

Now when you compare the value with null there is no ambiguity issue.

This also has the side effect of making the classes implicitly convertible to each other everywhere else, but based on the context that doesn't seem to be a bad thing.

like image 36
Servy Avatar answered Nov 12 '22 05:11

Servy


You can pass 2nd param as "object" and check its type before deciding which equality to do.

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;
}
like image 41
Konstantin Avatar answered Nov 12 '22 07:11

Konstantin