Operatori aritmetici predefiniti in C #

In che modo c # definisce +, -, *, / gli operatori per le classi che non sovraccaricano gli operatori? Ho implementato la seguente class. Senza sovraccaricare alcun operatore, gli operatori citati funzionano e funzionano come avrei dovuto implementare! Ecco il codice:

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

Ora prendi in considerazione questo pezzo di codice di utilizzo:

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

n3 valuta a 15! Questo succede anche con altri operatori!

n3 = n1 + n2 è valutato come segue:

  1. Innanzitutto viene determinato l’elenco degli operatori candidati, inclusi eventuali sovraccarichi definiti dall’utente ( ECMA-334, sezione 14.2.4 ). Nessuno si applica, quindi l’insieme di operatori candidati diventa l’operatore binario predefinito + . Se avessi definito il tuo operator+(Number, Number) questo è dove sarebbe stato selezionato. (Probabilmente vorrai implementarlo per evitare errori di arrotondamento dalla conversione avanti e indietro.)
  2. Ora la risoluzione di sovraccarico viene triggersta per determinare quale implementazione di + deve essere utilizzata (sezione 14.4.2). Questa è probabilmente la parte più complicata della specifica C #, ma non è necessario approfondire la questione in profondità – tutto ciò di cui abbiamo bisogno è la conoscenza che le conversioni implicite si applicano quando si seleziona un sovraccarico appropriato (14.4.2.1). Per le regole precise, devi anche leggere la sezione 13.4 sulle conversioni definite dall’utente.
  3. La lingua tratta le conversioni implicite definite dall’utente su un livello uniforms con conversioni incorporate. In questo caso, poiché esiste una conversione implicita da Number a float , l’unico overload candidato per + rimane dopo la risoluzione è float operator +(float, float) con conversioni implicite, quindi viene invocato.
  4. Il float risultante viene quindi convertito implicitamente in Number utilizzando l’altro operatore. Si noti che anche senza questo, si otterrebbe comunque un’aggiunta float , il risultato non verrebbe convertito. Il compilatore in realtà non “solleva” l’operatore, anche se l’effetto è più o meno lo stesso (il sollevamento avviene per versioni nullable dei tipi di valore, ma questa è un’altra storia).

Quando si mescolano i tipi con conversioni implicite, le cose possono diventare complicate. La risoluzione del sovraccarico è molto dura per fare la cosa giusta e le regole non sono ambigue, ma anche così può essere difficile vedere quando è coinvolta una conversione, quindi non abusare degli operatori di conversione impliciti. Le conversioni esplicite richiedono un numero maggiore di sequenze di tasti, ma è anche molto più facile dire quale operatore finirà per essere invocato. Questo è certamente vero quando si sta inizialmente sviluppando il tipo in modo da poter controllare quali operatori non sono ancora stati implementati (ma è necessario, per motivi di prestazioni o di precisione).