9

Dato questa classe con un operatore cast implicito:C'è un modo per eseguire il casting di tipo implicito dinamico in C#?

public class MyDateTime 
{ 
    public static implicit operator MyDateTime(System.Int64 encoded) 
    { 
     return new MyDateTime(encoded); 
    } 

    public MyDateTime(System.Int64 encoded) 
    { 
     _encoded = encoded; 
    } 
    System.Int64 _encoded; 
} 

Ora posso effettuare le seguenti operazioni:

long a = 5; 
MyDateTime b = a; 

ma non il seguente:

long f = 5; 
object g = f; 
MyDateTime h = g; 

Questo dà un tempo di compilazione:

Impossibile convertire implicitamente il tipo "oggetto" in "MyDateTime".

Ha senso per me.

Ora modificare l'esempio precedente come segue:

long f = 5; 
object g = f; 
MyDateTime h = (MyDateTime)g; 

Questo compila bene. Ora ho un runtime InvalidCastException:

Impossibile eseguire il cast oggetto di tipo 'System.Int64' di digitare MyDateTime'.

Questo mi dice che C# operatori del cast impliciti vengono applicate solo al momento della compilazione, e non vengono applicate quando il runtime .NET sta tentando di lanciare in modo dinamico un oggetto a un altro tipo.

Le mie domande:

  1. Ho ragione?
  2. C'è qualche altro modo per farlo?

Tra l'altro, l'applicazione completa è che sto usando Delegate.DynamicInvoke() per chiamare una funzione che prende un parametro MyDateTime, e il tipo di argomento sto passando a DynamicInvoke è un lungo.

risposta

13

Ho ragione?

Sì, sì. Per essere pignoli, dovresti dire "conversione implicita definita dall'utente" piuttosto che "cast implicito" - un cast è (quasi) sempre esplicito. Ma la tua deduzione che la risoluzione di sovraccarico sceglie quale conversione definita dall'utente per chiamare in fase di compilazione e non in fase di esecuzione è corretta.

C'è un altro modo per farlo?

Sì. In C# 4 se si digita il "oggetto" come "dinamico", si riavvia il compilatore in fase di esecuzione e si esegue nuovamente tutte le analisi sugli operandi come se i tipi di compilazione fossero i tipi di runtime correnti.Come puoi immaginare, questo non è economico, anche se siamo molto furbi nel caching e nel riutilizzo dei risultati se lo fai in un ciclo stretto.

+0

Solo per curiosità, quali sono le ragioni per cui gli operatori non si comportano più come i metodi in fase di runtime? Data la tua risposta, sembra che siano solo zucchero sintattico e non molto altro. A mio avviso, renderebbe C# ancora più potente se questi tipi di operatori sono promossi come membri di prima classe di qualsiasi tipo (il che significa che diventano parte di tutte le altre qualità orientate agli oggetti come l'ereditarietà, l'override e l'interfacciamento). Fare leva su questi in fase di esecuzione di default implicano importanti cambiamenti nella progettazione e nell'implementazione della lingua? – MarioDS

+1

@MDeSchaepmeester: hai ragione che c'è un po 'di disconnessione qui. Ad esempio, confronta il design di int in decimale. Puoi dire 'Func add = decimal.Add;' ma non c'è modo di fare lo stesso per int; devi dire 'Func add = (x, y) => x + y'. Sarebbe stato bello, credo che tutti i tipi di built-in fossero stati progettati come Decimal, e quindi il runtime o il compilatore potrebbe scegliere di ridurli a operazioni più fondamentali per motivi di prestazioni. Ma questo tipo di coerenza deriva davvero da una mentalità "funzionale". –

+1

@MDeSchaepmeester: Sospetto che i progettisti originali del runtime non stessero pensando a quel tipo di astrazione funzionale unificante durante la progettazione del sistema di tipi e le operazioni sui tipi integrati. E ovviamente è anche strano che decimal abbia sia un operatore + che un metodo Add. E non farmi nemmeno iniziare sulla dozzina di modi per rappresentare l'operazione di uguaglianza! È davvero un casino. La prossima volta che crei un framework da zero, prendi questa roba in anticipo. –

-2

So che questa è una domanda più vecchio, ma nel caso in cui nessun altro si imbatte lo stesso problema, questo sarà compilare ed eseguire bene:

long f = 5; 
object g = f; 
MyDateTime h = g as MyDateTime; 
+0

Funzionerà correttamente nel senso che non genererà un 'InvalidCastException', tuttavia' h' sarà 'null', che non è ciò che l'OP vuole o si aspetta. – MarioDS

Problemi correlati