Sono spesso in perdita per dare una risposta soddisfacente alle domande "perché".
Il motivo per cui il compilatore C# mostra questo comportamento è perché è (in questo caso almeno (*)) un'implementazione corretta della specifica C#.
La sezione 6.4.5 della specifica descrive come vengono analizzate le conversioni definite dall'utente. Una lettura attenta di quella sezione spiegherà perché la conversione esplicita a int è legale ma non a decimale.
In particolare, il relativo paragrafo è:
Trova l'insieme di applicabile definita dall'utente e sollevò operatori di conversione, U. Questo set è composto da operatori di conversione implicita o esplicita definita dall'utente e sollevato dichiarati dal classi o strutture in D che convertono da un tipo che comprende o racchiuso da S in un tipo che comprende o racchiuso da T. Se U è vuoto, la conversione non è definita e si verifica un errore in fase di compilazione.
Nel tuo caso, S è TwFix e T è int o decimale. L'unica conversione esplicita definita dall'utente su TwFix restituisce un float. int è compreso da float, ma decimal non è compreso da né comprende float. Quindi l'insieme U ha un membro in un caso ed è vuoto nell'altro. Quindi un caso produce un errore, come dice la specifica, e l'altro no.
Ho la sensazione che questa risposta non sia soddisfacente. In caso contrario, puoi riformulare la domanda in modo che non contenga la parola "perché"? Sono molto più bravo a rispondere alle domande "what" o "how" che alle domande "why".
(*) Il compilatore ha noti bug nel codice che calcola se un tipo comprende un altro allo scopo di determinare quali conversioni incorporate sono rilevanti quando si analizza la semantica di una particolare conversione definita dall'utente. In molti casi non stiamo deliberatamente riparando questi bug perché così facendo introdurrebbe un cambiamento sostanziale nel codice del mondo reale senza grandi vantaggi. Mi piacerebbe molto rivisitare questa sezione della specifica e riscriverla in modo da rimuovere il concetto di "tipo onnicomprensivo"; è un po 'strano nelle specifiche. E, come hai scoperto, produce questa stranezza, dove float è esplicitamente convertibile in decimale e decimale è esplicitamente convertibile in float, ma dal momento che nessuno dei due comprende l'altro, il codice di conversione esplicito definito dall'utente non gli piace. Tuttavia questa è una priorità molto bassa.
fonte
2010-05-10 22:26:59
La mia sensazione è che la domanda di fondo è perché (sì, lo so) il fatto che ci sia una conversione implicita da int a float dovrebbe influire sulle conversioni che si verificano nella direzione opposta (da TwFix32 a virgola mobile a int). Questo mi sembra che * dovrebbe * essere una conversione irrilevante in questo caso - ma chiaramente non lo è, perché riguarda l'involucro.Sospetto che la * reale * "perché" la risposta qui sia probabile, "Perché fa funzionare molti altri casi come previsto, al costo di questo tipo di stranezze". –
@Jon: corretto; se si pensa a queste regole dal punto di vista dell'analisi delle conversioni definite dall'utente su tipi * reference *, ha più senso; i tipi di riferimento non-interfaccia tipicamente non hanno situazioni come la situazione float/decimale. –