2014-09-25 22 views
11

Ho preso in prestito il codice qui sotto da another question (leggermente modificato), da utilizzare nel mio codice:Perché/quando è importante specificare un operatore come esplicito?

internal class PositiveDouble 
{ 
     private double _value; 
     public PositiveDouble(double val) 
     { 
      if (val < 0) 
       throw new ArgumentOutOfRangeException("Value needs to be positive"); 
      _value = val; 
     } 

     // This conversion is safe, we can make it implicit 
     public static implicit operator double(PositiveDouble d) 
     { 
      return d._value; 
     } 
     // This conversion is not always safe, so we're supposed to make it explicit 
     public static explicit operator PositiveDouble(double d) 
     { 
      return new PositiveDouble(d); // this constructor might throw exception 
     } 
} 

L'autore originale di questo codice aderisce correttamente alle avvertenze contenute nella documentazione implicit & explicit di MSDN, ma qui c'è la mia domanda: È sempre necessario explicit in un codice potenzialmente eccezionale?

Così, ho alcuni tipi nel mio codice (ad esempio, "Volume"), che derivano dalla PositiveDouble e mi piacerebbe essere in grado di impostare le istanze comodamente come la prima riga sotto:

Volume v = 10; //only allowed by implicit conversion 
Volume v = new Volume(10) //required by explicit conversion, but gets messy quick 

Essere obbligati a usare cast espliciti ovunque rende il codice molto meno leggibile. Come protegge l'utente? Nella semantica del mio programma, non mi aspetto mai un volume negativo; anzi, se mai dovesse succedere, mi aspetto che venga lanciata un'eccezione. Quindi, se utilizzo una conversione implicita e si getta, quali "risultati inaspettati" potrebbero clobber me?

+0

Sembra che cambiare l'operatore di conversione in implicito dovrebbe andare bene qui. – Botonomous

+1

Si consiglia, in particolare, in un'API pubblica. Impedisce alle persone di usare il cast senza accorgersene, risparmiando tempo nel debugging. Fare in modo che le persone notino il cast eviterà problemi. Dicono "oh, quindi pensi di essere intelligente rendendo tutto il cast implicito?" e tu dici "Se sai quello che stai facendo, non avrai problemi" - immagina una stufa che parte quando c'è qualcosa, perché "Essere costretti ad accendere la stufa ogni volta rende la cottura molto meno efficiente", e i produttori rispondono alle affermazioni con "allora non mettere le cose sopra" - solo meno drammatiche e senza le ustioni. – Theraot

risposta

14

La specifica del linguaggio C#, dice sotto 10.10.3 operatori di conversione:

Se una conversione definita dall'utente può dar luogo a eccezioni (ad esempio, perché l'argomento sorgente è fuori portata) o la perdita di informazioni (come scartare i bit di ordine più alto), quindi quella conversione dovrebbe essere essere definita come una conversione esplicita.

Inoltre, da MSDN: implicit (C# Reference):

In generale, gli operatori di conversione implicita non dovrebbero mai generare eccezioni e mai perdere le informazioni in modo che possano essere utilizzate in modo sicuro senza la consapevolezza del programmatore. Se un operatore di conversione non è in grado di soddisfare tali criteri, lo deve essere contrassegnato come esplicito per.

Considerando questo, il vostro operator PositiveDouble(double d)non dovrebbe essere contrassegnatoimplicit, come Volume v = -1 un'eccezione.

Quindi, per rispondere alla tua domanda:

è esplicito sempre necessario nel codice potenzialmente eccezionale?

No, non è necessario, ma è .

Confinante con l'opinione: se il codice è l'unico codice che utilizza questa conversione e la conversione implicita è più facile da leggere e/o mantenere, sentitevi liberi di usarlo.

Per quanto riguarda

Come ci si protegge l'utente?

See MSDN: explicit (C# Reference) cita:

Se un'operazione di conversione può causare eccezioni o perdere informazioni, si dovrebbe segnare esplicita. Ciò impedisce al compilatore di richiamare silenziosamente l'operazione di conversione con conseguenze potenzialmente impreviste.

Non riesco davvero a capire quando questo si verificherà, ma ancora una volta, se pensi di non convertire mai da un doppio negativo nel tuo codice da nessuna parte, questo non dovrebbe mai gettare.

+2

* "Non riesco proprio a capire quando ciò si verifica" * - Può accadere facilmente quando si passano oggetti con conversioni personalizzate a metodi framework che accettano tali argomenti. Non è ovvio nel codice che ciò accada a meno che tu (a) non sappia esattamente quale tipo di argomento accetta il metodo framework e (b) sappia che la conversione implicita esiste. – cdhowie

13

Le conversioni devono essere implicite solo se avranno sempre esito positivo. Se possono fallire o causare la perdita di informazioni, dovrebbero essere espliciti, perché ciò richiede che il chiamante dell'operazione di conversione indichi intenzionalmente che desiderano questa conversione e quindi sono pronti ad affrontare il risultato, qualunque esso sia.

Possiamo vedere questo nei tipi numerici primitivi del framework; l'assegnazione di a long è una conversione implicita, poiché avrà sempre esito positivo. L'altra direzione può causare uno OverflowException in un contesto controllato e può causare il troncamento (perdita di informazioni) in un contesto non controllato, pertanto è necessario indicare che si è intenzionata questa conversione mediante il casting esplicito.

Problemi correlati