Почему компилятор C # не вызывает неявный оператор приведения? - PullRequest
6 голосов
/ 26 декабря 2008

Предположим, у нас есть следующий тип:

struct MyNullable<T> where T : struct
{
    T Value;

    public bool HasValue;

    public MyNullable(T value)
    {
        this.Value = value;
        this.HasValue = true;
    }

    public static implicit operator T(MyNullable<T> value)
    {
        return value.HasValue ? value.Value : default(T);
    }
}

И попробуйте скомпилировать следующий фрагмент кода:

MyNullable<int> i1 = new MyNullable<int>(1);
MyNullable<int> i2 = new MyNullable<int>(2);

int i = i1 + i2;

Этот отрывок скомпилирован хорошо и без ошибок. i1 и i2 приводятся к целому числу, и вычисляется сложение.

Но если у нас есть следующий тип:

struct Money
{
    double Amount;
    CurrencyCodes Currency; /*enum CurrencyCode { ... } */

    public Money(double amount, CurrencyCodes currency)
    {
        Amount = amount;
        Currency = currency;
    }

    public static Money operator + (Money x, Money y)
    {
        if (x.Currency != y.Currency)
            // Suppose we implemented method ConvertTo
            y = y.ConvertTo(x.Currency); 

        return new Money(x.Amount + y.Amount, x.Currency);
    }
}

Попробуйте скомпилировать другой фрагмент кода:

MyNullable<Money> m1 = 
   new MyNullable<Money>(new Money(10, CurrenciesCode.USD));
MyNullable<Money> m2 = 
   new MyNullable<Money>(new Money(20, CurrenciesCode.USD));

Money m3 = m1 + m2;

А теперь вопрос, почему компилятор генерирует « ошибка CS0019: оператор« + »нельзя применить к операндам типа« MyNullable »и« MyNullable ' »?

Ответы [ 2 ]

10 голосов
/ 26 декабря 2008

Это интересный вопрос ... он работает, например, с Decimal, но не с TimeSpan, которые оба являются правильными типами .NET (в отличие от float и т. Д., Которые являются примитивами), и оба имеют оператор + , Любопытно!

Конечно, вы можете повернуть руку с помощью:

Money m3 = (Money)m1 + (Money)m2;

И если вы просто используете Nullable<T>, это, конечно, будет работать бесплатно - плюс вы получите поддержку компилятора + среды выполнения (бокса). Есть ли причина не использовать Nullable<T> здесь?

Я посмотрю на спецификации; тем временем вы можете подумать о повышении оператора до MyNullable<T>; при обычном Nullable<T> компилятор C # предоставляет «поднятые» операторы для операторов, поддерживаемых типом, но вы не можете сделать это самостоятельно. Лучшее, что вы можете сделать, это предложить все очевидные из них и надеяться, что тип поддерживает его ;-p Чтобы получить доступ к операторам с обобщениями, см. здесь , доступно для бесплатной загрузки здесь .

Обратите внимание, что вы, вероятно, захотите применить соответствующие "отмененные" чеки - т.е.

x + y => (x.HasValue && y.HasValue)
          ? new MyNullable<T>(x.Value + y.Value)
          : new MyNullable<T>();

Обновление

Различная обработка, по-видимому, относится к 14.7.4 (ECMA 334 v4) «Оператор сложения», где он предопределен для диапазона типов , включая десятичный (так что это был плохой тест me), поскольку согласно 14.2.4 (то же самое) «Разрешение перегрузки бинарных операторов», предопределенные операторы получают особое упоминание. Я не утверждаю, что понимаю это полностью.

9 голосов
/ 27 декабря 2008

Марк находится в правильных строках - это раздел 7.2.4 в спецификации C # 3.0 - Разрешение перегрузки двоичного оператора.

В основном шаги:

  • Нам нужно разрешить реализацию для "X + Y", где X и Y оба MyNullable<Money>.
  • Глядя на раздел 7.2.5 (возможные пользовательские операторы), мы получаем пустой набор, так как MyNullable<T> не перегружает +.
  • В п. 7.2.4 набор операторов-кандидатов является встроенным набором бинарных операторов для +, то есть int + int, десятичный + десятичный и т. Д.
  • Правила разрешения перегрузки в 7.4.3 применяются , затем . Когда мы делаем MyNullable<int> + MyNullable<int>, это работает из-за неявного преобразования каждого аргумента в int - но когда мы делаем MyNullable<Money> + MyNullable<Money>, это не работает, потому что Money + Money не работает в наборе операторов-кандидатов.
...