C# implicit conversions and == operator

10,687

Solution 1

The implicit operator only works for assignment.

You want to overload the equality (==) operator, as such:

class a
{
    public static bool operator ==(a x, b y)
    {
        return x == y.a;
    }

    public static bool operator !=(a x, b y)
    {
        return !(x == y);
    }
}

class b
{
    public a a{get;set;}
    public static implicit operator a(b b)
    {
        return b.a;
    }
}

This should then allow you to compare two objects of type a and b as suggested in your post.

var x = new a();
var y = new b();
bool c = (x == y); // compiles

Note:

I recommmend simply overriding the GetHashCode and Equals method, as the compiler warns, but as you seem to want to supress them, you can do that as follows.

Change your class declaration of a to:

#pragma warning disable 0660, 0661
class a
#pragma warning restore 0660, 0661
{
    // ...
}

Solution 2

Is it possible to use == operator on different type instances, where one can implicitly convert to another?

Yes.

What did i miss?

Here's the relevant portion of the specification. You missed the highlighted word.

The predefined reference type equality operators require [that] both operands are reference-type values or the literal null. Furthermore, a standard implicit conversion exists from the type of either operand to the type of the other operand.

A user-defined conversion is by definition not a standard conversion. These are reference types. Therefore, the predefined reference type equality operator is not a candidate.

If types must be the same calling ==, then why [double == int] works?

Your supposition that the types must be the same is incorrect. There is a standard implicit conversion from int to double and there is an equality operator that takes two doubles, so this works.

I think you also missed this bit:

It is a compile-time error to use the predefined reference type equality operators to compare two references that are known to be different at compile-time. For example, if the compile-time types of the operands are two class types A and B, and if neither A nor B derives from the other, then it would be impossible for the two operands to reference the same object. Thus, the operation is considered a compile-time error.

Solution 3

I would imagine that you need to actually override the == operator for the types you are interested in. Whether the compile/runtime will still complain even if the types are implicity convertable is something you'll have to experiment with.

public static bool operator ==(a a, b b)
    {
        //Need this check or we can't do obj == null in our Equals implementation
        if (((Object)a) == null)
        {
            return false;
        }
        else
        {
            return a.Equals(b);
        }
    }

Alternatively just use Equals implementations like ole6ka suggests and ensure that the implementation does the type casting you need.

Share:
10,687
Arnis Lapsa
Author by

Arnis Lapsa

Updated on July 27, 2022

Comments

  • Arnis Lapsa
    Arnis Lapsa 2 months

    Some code for context:

    class a
    {
    
    }
    
    class b
    {
        public a a{get;set;}
        public static implicit operator a(b b)
        {
            return b.a;
        }
    }
    
      a a=null;
      b b=null;
      a = b;
    
      //compiler: cannot apply operator '==' to operands of type tralala...
      bool c = a == b; 
    

    Is it possible to use == operator on different type instances, where one can implicitly convert to another? What did i miss?

    Edit:
    If types must be the same calling ==, then why

    int a=1;
    double b=1;
    bool c=a==b; 
    

    works?

    • Rowland Shaw
      Rowland Shaw over 13 years
      I'd assume your int/double example works because they are value types, and not reference types...
    • Arnis Lapsa
      Arnis Lapsa over 13 years
      That can be a reason. Only problem is - if so, it doesn't explain why exactly reference type can't perform conversion implicitly just like value types can.
  • Arnis Lapsa
    Arnis Lapsa over 13 years
    This won't be useful in particular case, cause i'm abusing lambdas and builder pattern to create dynamic property setter like this: factory.Object.With(object=>object.MyProp==newPropValue).Cre‌​ate()
  • Ahmed
    Ahmed over 13 years
    and in this case the a == b expression will compile with no problems.
  • Arnis Lapsa
    Arnis Lapsa over 13 years
    This seems like correct answer. Kind a figured out this too. Only - i think that operator overloading would be overkill in this case (it demands gethash() and equals() function overloading too :/ ).
  • Noldorin
    Noldorin over 13 years
    Yeah, there are no restrictions on defining or using custom (overloaded) operators on user-defined types.
  • Noldorin
    Noldorin over 13 years
    @Arnis L: They are only warnings fortunately. You can overriden them if you like (Equals can have the same logic as == and GetHashCode can just return a.GetHashCode() ^ b.GetHashCode()), or you can ignore/supress the warnings if you don't care.
  • Arnis Lapsa
    Arnis Lapsa over 13 years
    Is there a way to suppress warning through code (have seen something like that somewhere)?
  • Noldorin
    Noldorin over 13 years
    @Arnis L: Yep, see my updated post. Not sure it's that much more effort just to override them with a simple implementation however...
  • Arnis Lapsa
    Arnis Lapsa over 13 years
    Enlighten me why that code i added after "Edit:" works and you will surely get accepted answer. :)
  • Noldorin
    Noldorin over 13 years
    Oh right, I missed that bit of your question, sorry. I believe it's a compiler-specific feature (there are no operator overloads defined in System.Int32 or System.Double). In this case, b (the double) gets converted into an int before equating the objects of the same type. (It may be the other way around - a simple test will tell you.) Hopefully this all makes sense to you now.
  • Eric Lippert
    Eric Lippert over 13 years
    The int gets converted to a double. If the double were converted to int then double "2.1" would be equal to int "2"!
  • Noldorin
    Noldorin over 13 years
    @Eric: Yeah, a widening rather than a narrowing conversion makes a lot more sense. The order of the operands is irrelevant, too.