2012-02-29 7 views
6

questione connessa: Accessing a Class property without using dot operatorCasting mia classe di Int64, Doppio ecc

Ho creato una classe chiamata MyDouble assomiglia a questo

class MyDouble 
{ 
    double value; 
    //overloaded operators and methods 
} 

Sono in grado di fare tutti i tipi di operazioni su MyDouble. Esempi:

MyDouble a = 5.0; 
a += 3.0; 
...etc 

Tuttavia, questo getta ancora un errore

MyDouble a = 5.0; 
long b = (Int64)a; //error 
long b = (int64)a.value; //works 

Come posso definirla tale che un'operazione come (Int64)a converte automaticamente in (Int64)a.value? Non voglio che l'utente debba mai preoccuparsi dell'esistenza della proprietà value.

+0

Perché si usano sia 'long' che' Int64'? Uno è un aloas per l'altro e penso che il modo più idiomatico sia usare gli alias se esistono al posto dei nomi dei tipi. – Joey

risposta

9

Affinché questa conversione funzioni, è necessario un explicit conversion in Int64.

Questo sarebbe simile:

class MyDouble 
{ 
    double value; 

    public static explicit operator Int64(MyDouble value) 
    { 
     return (Int64)value.value; 
    } 
} 
+0

Perfetto, grazie. – xbonez

+0

Perché dovrebbe essere esplicito? Anche una conversione implicita funziona e il cast diventa facoltativo. – Jay

+0

@Jay Si * potrebbe * eseguire un'operazione implicita, ma l'OP ha mostrato incluso l'operatore di conversione. Personalmente, tendo a evitare le conversioni implicite a meno che non abbiano molto senso (la conversione implicita da doppia a lunga sembra una cattiva idea, però). –

1

C'è una conversione esplicita da double a Int64, ma non dalla tua classe a Int64. tutto ciò che devi fare è definirne uno. Oppure, se hai una conversione dalla tua classe al raddoppio, quale suppongo tu faccia, potresti fare questo:

lungo x = (lungo) (doppio) a;

Tuttavia, questo è ingombrante; Definirei l'operatore di conversione esplicita.

La conversione deve essere esplicita, non implicita, a meno che non si abbia una buona ragione per renderla esplicita.

La conversione definita dalla lingua da doppio a lungo è esplicita perché la conversione potrebbe causare la perdita di informazioni. Puoi perdere informazioni con questa conversione perché ci sono alcuni doppi, come 0.5, che non convergono esattamente a lungo. Questa è chiamata una conversione di restringimento .

Con le conversioni definite dalla lingua, le conversioni di restringimento sono esplicite. Se fossero impliciti, i programmatori potrebbero perdere accidentalmente informazioni assegnando un valore di un tipo a una variabile di un altro tipo. Definire questa conversione come implicita viola quel principio del tutto ragionevole, quindi ci dovrebbe essere un caso convincente per farlo.

Ecco un esempio che mostra il valore di questo principio. Se il restringimento delle conversioni fosse implicito, renderebbe il codice più fragile. Supponiamo che la conversione da doppia a int sia implicita:

class Family 
{ 
    ICollection<Person> Children { get; set; } 
} 

int GetAverageNumberOfChildren(IEnumerable<Family> families) 
{ 
    return families.Sum(f => f.Children.Count)/families.Count(); 
} 

void SomeMethod(IEnumerable<Family> families) 
{ 
    int averageNumberOfChildren = GetAverageNumberOfChildren(families); 
    //... 
} 

Oops! Abbiamo un bug! GetAverageNumberOfChildren dovrebbe restituire un doppio! Risolviamolo!

double GetAverageNumberOfChildren(IEnumerable<Family> families) 
{ 
    return families.Average(f => f.Children.Count); 
} 

Wow, tutto si compila e funziona! Di sicuro contento che abbiamo beccato quell'insetto!

Ma, purtroppo, no. Abbiamo ancora un bug!SomeMethod converte implicitamente il doppio in un valore int, quindi, se il valore previsto potrebbe essere 2.4, il valore effettivo è 2.

Poiché la conversione da doppio a int è esplicita, il compilatore ci salva da noi stessi. Dopo aver corretto GetAverageNumberOfChildren, , il programma errato non viene compilato.

Ora, se la classe MyDouble aveva un po 'di convalida che limitato a valori interi con una gamma uguale o inferiore alla gamma di long, allora si sarebbe sicuro per effettuare la conversione implicita. Ma in quel caso, ovviamente, dovresti usare long, non double.

1

Una conversione implicita funzionerà come una conversione esplicita.

public static implicit operator long(MyDouble m) 
{ 
    return (long) m.value; 
} 

Con questo in luogo si può fare:

long b = (Int64) a; 

o semplicemente

long b = a; 

Questo è solo per illustrare che la conversione non deve essere esplicita. Come notato, tuttavia, dovrebbe essere essere esplicito a causa del potenziale per la perdita di dati.

+0

Questo è vero, ma pericoloso. Vedi la mia risposta modificata per una spiegazione. – phoog

+0

@phoog ho capito. Stavo solo prendendo in considerazione il linguaggio "tu * hai bisogno * di una conversione esplicita". – Jay

+0

Abbastanza giusto; Ho solo pensato che se stiamo discutendo dell'esistenza di conversioni implicite, sarebbe saggio discutere i motivi per rendere esplicite le conversioni di restringimento. Altrimenti qualcuno potrebbe essere tentato di implementare una conversione che dovrebbe essere esplicita come una conversione implicita "perché è più semplice" o "perché rende il mio codice più pulito", senza considerare la maggiore probabilità di scrivere programmi buggati. – phoog