2016-02-28 15 views
5

Perché è possibile una conversione esplicita da double a Foo, anche se Foo ha definito solo una conversione esplicita da a ?Perché il compilatore converte implicitamente un double in int quando esiste un operatore esplicito definito dall'utente da int a Foo?

Perché nel mio caso double è convertito implicitamente in un int?

using System; 

class Program 
{ 
    static void Main(string[] args) 
    { 
     double doub = 15.7; 
     Foo foo = (Foo)doub; 
     Console.WriteLine(foo.value); //writes "15" 
    } 
} 

struct Foo 
{ 
    public int value; 
    public static explicit operator Foo(int val) //no matter if implicit 
    { 
     return new Foo { value = val }; 
    } 
} 
+0

questo è esplicito. se provi "operatore implicito Foo (int val)' vedrai che non puoi scrivere 'Foo foo = doub;' ... –

+0

@ M.kazemAkhgary Questo codice sta causando un errore. http://ideone.com/ttBLLX Ma con 'operatore pubblico statico implicito Foo (int val)' 'Foo a = (Foo) dubbio;' funziona – Alex78191

+4

Le risposte date sono buone. Per ulteriori informazioni, vedere https://blogs.msdn.microsoft.com/ericlippert/2007/04/16/chained-user-defined-explicit-conversions-in-c/ e https://blogs.msdn.microsoft.com/ericlippert/2007/04/18/chained-user-defined-explicit-conversions-in-c-part-two/e https://blogs.msdn.microsoft.com/ericlippert/2007/04/20/chained- conversioni esplicite definite dall'utente-in-c-part-three/ –

risposta

1

La relativa sezione delle specifiche C# è

La sezione è lunga, ma distilla a questo: si sta definendo una conversione esplicita con (Foo)doub, e dal momento che stai usando una conversione esplicita il compilatore sceglierà le conversioni disponibili più specifiche, incluse le conversioni che sono solo esplicite, per fare i passaggi intermedi lungo la conversione percorso (se disponibili).

Se U contiene esattamente un operatore di conversione definito dall'utente che converte da SX a TX, allora questo è il più specifica conversione operatore. Se non esiste alcun operatore di questo tipo o se esiste più di uno di questi operatori , la conversione è ambigua e si verifica un errore in fase di compilazione. In caso contrario, viene applicata la conversione definita dall'utente:

Se S non è SX, viene eseguita una conversione esplicita standard da S a SX.
L'operatore di conversione definito dall'utente più specifico è invocato per la conversione da SX a TX.
Se TX non è T, viene eseguita una conversione esplicita standard da TX a T.

(sottolineatura mia)

Qui S è il tipo di origine e T è il tipo di destinazione, mentre SX è il tipo fonte più specifico definito nelle operatori espliciti del tipo di destinazione (ie; Foo) e TX è il tipo di destinazione più specifico definito negli operatori espliciti di T.

Qui una conversione esplicita esiste da double a int ed è quindi scelto come il più appropriato per convertire dal tipo di argomento sorgente (double -- S) per il tipo argomento di input dell'operatore esplicito (int -- SX). Non è necessario che sia esplicito poiché sei già stato esplicito sulla conversione in Foo.

Questo funziona solo perché non ci sono alternative ambigue. Se è stato definito Foo avere:

struct Foo 
{ 
    public int value; 
    public uint uvalue; 
    public static explicit operator Foo(int val) 
    { 
     return new Foo { value = val }; 
    } 


    public static explicit operator Foo(uint val) 
    { 
     return new Foo { uvalue = val }; 
    } 
} 

per esempio, questo produce un errore di compilazione (con lo stesso Main) di:

errore Foo 1 ambigui definiti dall'utente conversioni.operatore esplicito Foo (uint)' e 'operatore Foo.explicit Foo (int)' durante la conversione da 'doppio' a 'Foo'

Ancora una volta, questo è il libro (per il primo comma citato), in quanto l'insieme di conversioni disponibili U contiene ora due conversioni esplicite ugualmente valide e il compilatore non può decidere se intendi richiamare la conversione int o la conversione uint. Nell'esempio iniziale c'è solo una volta la scelta, ed è chiaro, così il compilatore lo prende.

8

Credo che questo sia illustrato nella sezione 6.4.3 della specifica del linguaggio C# 5.

Un primo accenno è dato in sezione 6.2.8 Definito dall'utente conversioni esplicite (sottolineatura mia):

Una conversione esplicita definita dall'utente consiste in un norma opzionale conversione esplicita, seguita dalla realizzazione di un implicito o esplicito operatore di conversione definita dall'utente, seguito da un altro di serie opzionale conversione esplicita

Si noti come non o ne ma potenzialmente si verificano tre conversioni.

Ora, per sapere che cosa è un 'conversione esplicita standard' dobbiamo guardare alla sezione di 6.2.3 Standard explicit conversions:

Le conversioni esplicite standard sono tutte le conversioni implicite standard più il sottoinsieme delle esplicite conversioni per i quali un esiste una conversione implicita standard opposta. In altre parole, se un implicito conversione standard esiste da un tipo A ad un tipo B, poi una conversione esplicita norma esiste da tipo A a tipo B e dal tipo B al tipo A.

e guardando indietro a sezione 6.3.1 Standard implicit conversions possiamo vedere che questa è una parte di esso:

  • conversioni numeriche implicite (§6.1.2)

In altre parole: una conversione numerica esplicita (come double -> int) può essere applicata prima della conversione definita dall'utente.

Se ora guardiamo 6.4.3 Evaluation of user-defined conversions vediamo quanto segue (sottolineatura mia):

In primo luogo, se necessario, l'esecuzione di una conversione standard dal tipo di origine al tipo di operando dell'operatore di conversione userdefined o revocato

Successivamente, richiamare l'operatore di conversione definito dall'utente o sollevato per eseguire la conversione.

Infine, se necessario, eseguire una conversione standard dal tipo di risultato dell'operatore di conversione sollevato dall'utente al tipo di destinazione.

Che è esattamente ciò che accade nel vostro scenario.

+2

In effetti puoi ottenere fino a * quattro * conversioni coinvolgendo conversioni annullabili: https://blogs.msdn.microsoft.com/ericlippert/2007/04/16/concatenato-definito dall'utente-conversioni esplicite-in-c/ –

+0

Ah, non ero sicuro se questo contasse come una conversione considerando che il C# LS lo menziona come "* Ai fini di questo passaggio, se uno dei due il tipo di origine o di destinazione è un tipo nullable, il loro tipo sottostante viene invece utilizzato * ". Buono a sapersi! –

Problemi correlati