C # неявные преобразования и оператор == - PullRequest
7 голосов
/ 21 мая 2009

Код для контекста:

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; 

Можно ли использовать оператор == в экземплярах разных типов, где один может неявно преобразовываться в другой? Что я упустил?

Edit:
Если типы должны быть одинаковыми, вызывая ==, то почему

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

работает

Ответы [ 5 ]

14 голосов
/ 21 мая 2009

Оператор implicit работает только для назначения.

Вы хотите перегрузить оператор равенства (==), например:

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

Это должно позволить вам сравнить два объекта типа a и b, как предлагается в вашем посте.

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

Примечание:

Я рекомендую просто переопределить метод GetHashCode и Equals, как предупреждает компилятор, но, как вы, похоже, хотите их подавить, вы можете сделать это следующим образом.

Измените объявление класса a на:

#pragma warning disable 0660, 0661
class a
#pragma warning restore 0660, 0661
{
    // ...
}
11 голосов
/ 21 мая 2009

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

Да.

Что я пропустил?

Вот соответствующая часть спецификации. Вы пропустили выделенное слово.

Предопределенное равенство типов ссылок операторы требуют, чтобы оба операнда являются значениями ссылочного типа или буквальный ноль. Кроме того, стандарт неявное преобразование существует из тип любого операнда к типу другой операнд.

Определяемое пользователем преобразование по определению не является стандартным преобразованием. Это ссылочные типы. Поэтому предопределенный оператор равенства ссылочного типа не является кандидатом.

Если типы должны быть одинаковыми, вызывая ==, тогда почему [double == int] работает?

Ваше предположение, что типы должны быть одинаковыми, неверно. Существует стандартное неявное преобразование из int в double, и есть оператор равенства, который принимает два double, поэтому это работает.

Я думаю, вы тоже пропустили этот бит:

Это ошибка времени компиляции, чтобы использовать предопределенное равенство ссылочного типа операторы для сравнения двух ссылок которые, как известно, отличаются в время компиляции. Например, если типы операндов во время компиляции два типа классов A и B, и если ни А, ни В не происходят из другой, то это было бы невозможно для два операнда ссылаются на одно и то же объект. Таким образом, операция считается ошибкой во время компиляции.

1 голос
/ 21 мая 2009

Я полагаю, что вам нужно переопределить оператор == для интересующих вас типов. Будет ли жаловаться компиляция / среда выполнения, даже если типы конвертируемы, - это то, с чем вам придется экспериментировать.

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

В качестве альтернативы просто используйте реализации Equals, как предлагает ole6ka, и убедитесь, что реализация выполняет приведение типов, которое вам нужно.

0 голосов
/ 21 мая 2009

http://msdn.microsoft.com/en-us/library/8edha89s.aspx

В каждом случае один параметр должен быть того же типа, что и класс или структура который объявляет оператор (...)

0 голосов
/ 21 мая 2009

Используйте это

 bool c = a.Equals(b);
...