Qual è la differenza tra casting e coercizione?

Ho visto entrambi i termini essere usati quasi in modo intercambiabile in varie spiegazioni online, e la maggior parte dei libri di testo che ho consultato non sono del tutto chiari sulla distinzione.

C’è forse un modo semplice e chiaro per spiegare la differenza che voi ragazzi conoscete?

Conversione di tipo (anche noto come cast di tipo )

Per utilizzare un valore di un tipo in un contesto che si aspetta un altro.

Cast di tipo non convertito (talvolta noto come type pun )

Una modifica che non modifica i bit sottostanti.

Coercizione

Processo mediante il quale un compilatore converte automaticamente un valore di un tipo in un valore di un altro tipo quando quel secondo tipo è richiesto dal contesto circostante.

Tipo di conversione :

La conversione di parole si riferisce al cambiamento implicito o esplicito di un valore da un tipo di dati a un altro, ad esempio un numero intero a 16 bit per un numero intero a 32 bit.

La parola coercizione è usata per indicare una conversione implicita.

Il cast di parole si riferisce in genere a una conversione di tipo esplicito (al contrario di una conversione implicita), indipendentemente dal fatto che si tratti di una reinterpretazione di un pattern di bit o di una conversione reale.

Quindi, la coercizione è implicita, il cast è esplicito e la conversione è una di queste.


Pochi esempi (dalla stessa fonte ):

Coercizione (implicita):

double d; int i; if (d > i) d = i; 

Cast (esplicito):

 double da = 3.3; double db = 3.3; double dc = 3.4; int result = (int)da + (int)db + (int)dc; //result == 9 

Gli usi variano, come si nota.

I miei usi personali sono:

  • Un “cast” è l’uso di un operatore di cast . Un operatore cast indica al compilatore che (1) questa espressione non è nota per il tipo specificato, ma ti prometto che il valore sarà di quel tipo in fase di esecuzione; il compilatore tratta l’espressione come del tipo dato e il runtime genera un errore se non lo è, oppure (2) l’espressione è di un tipo diverso interamente, ma esiste un modo ben noto per associare le istanze del tipo di espressione con istanze del tipo cast-to. Il compilatore viene istruito per generare codice che esegue la conversione. Il lettore attento noterà che questi sono contrari, che penso sia un trucco pulito.

  • Una “conversione” è un’operazione con cui un valore di un tipo viene trattato come un valore di un altro tipo, di solito un tipo diverso, sebbene una “conversione di id quadro” sia ancora una conversione, tecnicamente parlando. La conversione può essere “modifica di una rappresentazione”, come int a raddoppiare, o potrebbe essere “rappresentazione che preserva” come una stringa all’object. Le conversioni possono essere “implicite”, che non richiedono un cast, o “esplicite”, che richiedono un cast.

  • Una “coercizione” è una conversione implicita che cambia la rappresentazione.

La trasmissione è il processo mediante il quale si considera un tipo di object come un altro tipo, la coercizione è la conversione di un object in un altro.

Nota che nel precedente processo non è coinvolta alcuna conversione, hai un tipo che vorresti trattare come un altro, ad esempio, hai 3 oggetti diversi che ereditano da un tipo di base, e hai un metodo che lo prenderà tipo di base, in qualsiasi momento, se ora si specifica il tipo di figlio, è ansible eseguire il CAST su quello che è e utilizzare tutti i metodi e le proprietà specifici di quell’object e che non creerà una nuova istanza dell’object.

D’altra parte, la coercizione implica la creazione di un nuovo object in memoria del nuovo tipo e quindi il tipo originale verrà copiato su quello nuovo, lasciando entrambi gli oggetti in memoria (fino a quando i Garbage Collector non se ne vanno o entrambi) .

Di seguito è riportato un post dal seguente articolo :

La differenza tra coercizione e casting è spesso trascurata. Posso capire perché; molte lingue hanno la stessa (o simile) syntax e terminologia per entrambe le operazioni. Alcune lingue possono anche riferirsi a qualsiasi conversione come “casting”, ma la seguente spiegazione fa riferimento ai concetti nel CTS.

Se si sta tentando di assegnare un valore di qualche tipo a un percorso di un tipo diverso, è ansible generare un valore del nuovo tipo che ha un significato simile all’originale. Questa è coercizione. Coercion ti consente di utilizzare il nuovo tipo creando un nuovo valore che in qualche modo assomiglia all’originale. Alcune coercizioni possono scartare i dati (ad es. Convertire l’int 0x12345678 nel breve 0x5678), mentre altri potrebbero non farlo (ad esempio, la conversione dell’int 0x00000008 nel breve 0x0008 o il lungo 0x0000000000000008).

Ricorda che i valori possono avere più tipi. Se la situazione è leggermente diversa e si desidera selezionare solo uno dei tipi di valore, la trasmissione è lo strumento per il lavoro. La trasmissione indica semplicemente che desideri operare su un tipo particolare che include un valore.

La differenza a livello di codice varia da C # a IL. In C #, sia il casting che la coercizione appaiono abbastanza simili:

 static void ChangeTypes(int number, System.IO.Stream stream) { long longNumber = number; short shortNumber = (short)number; IDisposable disposableStream = stream; System.IO.FileStream fileStream = (System.IO.FileStream)stream; } 

A livello di IL sono piuttosto diversi:

 ldarg.0 conv.i8 stloc.0 ldarg.0 conv.i2 stloc.1 ldarg.1 stloc.2 ldarg.1 castclass [mscorlib]System.IO.FileStream stloc.3 

Per quanto riguarda il livello logico, ci sono alcune importanti differenze. La cosa più importante da ricordare è che la coercizione crea un nuovo valore, mentre il cast non lo fa. L’id quadro del valore originale e il valore dopo la fusione sono gli stessi, mentre l’id quadro di un valore forzato differisce dal valore originale; la coersione crea una nuova istanza distinta, mentre il cast non lo fa. Un corollario è che il risultato del casting e l’originale saranno sempre equivalenti (sia in termini di id quadro che di uguaglianza), ma un valore coercitivo può o non può essere uguale all’originale e non condivide mai l’identity framework originale.

È facile vedere le implicazioni della coercizione negli esempi sopra, poiché i tipi numerici sono sempre copiati per valore. Le cose diventano un po ‘più complicate quando lavori con i tipi di riferimento.

 class Name : Tuple { public Name(string first, string last) : base(first, last) { } public static implicit operator string[](Name name) { return new string[] { name.Item1, name.Item2 }; } } 

Nell’esempio seguente, una conversione è un cast, mentre l’altra è una coercizione.

 Tuple tuple = name; string[] strings = name; 

Dopo queste conversioni, la tupla e il nome sono uguali, ma le stringhe non sono uguali a nessuno di essi. Potresti rendere la situazione leggermente migliore (o leggermente più confusa) implementando Equals () e operator == () nella class Name per confrontare un Nome e una stringa []. Questi operatori risolverebbero il problema di confronto, ma avresti comunque due istanze separate; qualsiasi modifica alle stringhe non si rifletterà nel nome o nella tupla, mentre le modifiche a uno dei nomi o tuple si rifletteranno nel nome e nella tupla, ma non nelle stringhe.

Anche se l’esempio precedente ha lo scopo di illustrare alcune differenze tra casting e coercizione, è anche un ottimo esempio del perché dovresti essere estremamente cauto nell’usare gli operatori di conversione con i tipi di riferimento in C #.

Il cast conserva il tipo di oggetti. La coercizione no.

La coercizione sta prendendo il valore di un tipo NON compatibile con l’assegnazione e la conversione in un tipo compatibile con l’assegnazione. Qui eseguo una coercizione perché Int32 NON eredita da Int64 … quindi NON è compatibile con l’assegnazione. Questa è una coercizione crescente (nessun dato perso). Una coercizione crescente è anche una conversione implicita. Una coercizione esegue una conversione.

 void Main() { System.Int32 a = 100; System.Int64 b = a; b.GetType();//The type is System.Int64. } 

La trasmissione consente di trattare un tipo come se fosse di un tipo diverso pur preservando il tipo .

  void Main() { Derived d = new Derived(); Base bb = d; //bN();//INVALID. Calls to the type Derived are not possible because bb is of type Base bb.GetType();//The type is Derived. bb is still of type Derived despite not being able to call members of Test } class Base { public void M() {} } class Derived: Base { public void N() {} } 

Fonte: The Common Language Infrastructure Standard annotato da James S. Miller

Ora, ciò che è strano è che la documentazione di Microsoft su Casting non sia allineata con la definizione della specifica ecma-335 di Casting.

Conversioni esplicite (conversioni): le conversioni esplicite richiedono un operatore di cast. La trasmissione è necessaria quando le informazioni potrebbero andare perse nella conversione o quando la conversione potrebbe non riuscire per altri motivi. Esempi tipici includono la conversione numerica in un tipo con meno precisione o un intervallo più piccolo e la conversione di un’istanza di class base in una class derivata.

… Sembra che Coercions non vada in fumo.

Per esempio,

  object o = 1; int i = (int)o;//Explicit conversions require a cast operator i.GetType();//The type has been explicitly converted to System.Int32. Object type is not preserved. This meets the definition of Coercion not casting. 

Chissà? Forse Microsoft sta controllando se qualcuno legge questa roba.