2016-12-11 4 views
3

Как C# определить +, -, *,/операторов для классов, у которых нет перегруженных операторов? Я реализовал следующий класс. Без перегрузки каких-либо операторов упомянутые операторы работают, и они работают так, как я собирался реализовать! Вот код:Арифметические операторы по умолчанию в C#

class Number 
{ 
    private float mDecimal; 
    public float Decimal 
    { 
     get { return mDecimal; } 
    } 

    private int mOrder; 
    public int Order 
    { 
     get { return mOrder; } 
    } 

    public Number(float dec, int pow) 
    { 
     mDecimal = dec; 
     mOrder = pow; 
    } 

    public Number Power(Number number) 
    { 
     throw new NotImplementedException(); 
    } 

    public static implicit operator Number(float num) 
    { 
     int pow = 0; 
     while (num > 1000) 
     { 
      num *= 0.1f; 
      ++pow; 
     } 

     return new Number(num, pow); 
    } 

    public static implicit operator float(Number num) 
    { 
     float result = num.mDecimal; 
     for (int i = 0; i < num.mOrder; ++i) 
      result *= 10; 
     return result; 
    } 
} 

Теперь принять во внимание этот кусок кода использования:

Number n1 = 5; 
Number n2 = 10; 
Number n3 = n1 + n2; 

n3 оценивает 15! Это случается и с другими операторами!

+5

Это потому, что вы определили 'implicit operator float' - поэтому оператор' + 'будет неявно преобразовывать ваши значения из' Number' в 'float' (' System.Single'), выполнять добавление, а затем конвертировать назад , – Dai

+1

Разве вы даже не пытались помещать точку разрыва в неявные операторы, которые были единственной возможной причиной этого? – Andrew

+0

@ Андрей Я новичок в C#. Мой фон - C++, который не работает в таких ситуациях неявно. Итак, не зная тип, так как ** Number ** конвертируется в float, он использует float? Я поместил другие операторы преобразования для другого настраиваемого класса, но он снова использует операторы float. Как компилятор выбирает, какое преобразование нужно сделать для обеспечения арифметических операторов? – Klaus

ответ

6

n3 = n1 + n2 вычисляется следующим образом:

  1. Во-первых, список операторов-кандидатов определяется, в том числе любых определенных пользователем перегрузкам (ECMA-334, section 14.2.4). Не применяются, поэтому набор операторов-кандидатов становится предопределенным двоичным оператором +. Если бы вы определили свой собственный operator+(Number, Number), там он был бы выбран. (Вероятно, вы захотите его реализовать, чтобы предотвратить ошибки округления от обратного преобразования.)
  2. Теперь перегрузка разрешается, чтобы определить, какая реализация + должна использоваться (раздел 14.4.2). Это, вероятно, самая сложная часть спецификации C#, но нам не нужно углубляться в нее очень глубоко - все, что нам нужно, это знание о том, что неявные преобразования применяются при выборе соответствующей перегрузки (14.4.2.1). Для точных правил вам также потребуется прочитать раздел 13.4 о пользовательских преобразованиях.
  3. Язык рассматривает пользовательские неявные преобразования на четной основе со встроенными преобразованиями. В этом случае, поскольку существует неявное преобразование от Number до float, единственная перегрузка кандидата для +, оставшаяся после разрешения, равна float operator +(float, float) с неявными преобразованиями, поэтому она вызывается.
  4. В результате float затем неявно преобразуется в Number с использованием другого оператора. Обратите внимание, что даже без этого вы все равно получите дополнение float, результат просто не будет преобразован обратно. Компилятор фактически не «поднимет» оператора, хотя эффект почти такой же (подъем действительно для нулевых версий типов значений, но это уже другая история).

При смешивании типов, имеющих неявные преобразования, все может стать сложным. Разрешение перегрузки очень тяжело делает правильную вещь, и правила недвусмысленны, но даже это может быть трудно понять, когда происходит преобразование, поэтому не злоупотребляйте неявными операторами преобразования. Явные преобразования требуют немного больше нажатий клавиш, но также гораздо легче сказать, какой оператор будет вызван. Это, безусловно, верно, когда вы изначально разрабатываете тип, чтобы вы могли проверить, какие операторы вы еще не реализовали (но должны, по соображениям производительности или точности).

+0

Это именно тот тип ответа, который можно было бы использовать более чем одним способом. – Klaus

Смежные вопросы