Casting diretto vs operatore ‘as’?

Considera il seguente codice:

void Handler(object o, EventArgs e) { // I swear o is a string string s = (string)o; // 1 //-OR- string s = o as string; // 2 // -OR- string s = o.ToString(); // 3 } 

Qual è la differenza tra i tre tipi di casting (okay, il terzo non è un casting, ma ottieni l’intento). Quale dovrebbe essere preferito?

 string s = (string)o; // 1 

Genera InvalidCastException se o non è una string . Altrimenti, assegna o a s , anche se o è null .

 string s = o as string; // 2 

Assegna null a se if o non è una string o se o è null . Per questo motivo, non è ansible utilizzarlo con i tipi di valore (l’operatore non potrebbe mai restituire null in quel caso). Altrimenti, assegna o a s .

 string s = o.ToString(); // 3 

Provoca una NullReferenceException se o è null . Assegna qualunque cosa o.ToString() restituisce a s , indipendentemente dal tipo o .


Utilizza 1 per la maggior parte delle conversioni: è semplice e diretto. Tendo quasi mai a usare 2 poiché se qualcosa non è del tipo giusto, di solito mi aspetto che si verifichi un’eccezione. Ho visto solo la necessità di questo tipo di funzionalità return-null con librerie mal progettate che utilizzano codici di errore (ad es. Return null = error, invece di usare eccezioni).

3 non è un cast ed è solo un’invocazione di metodo. Usalo per quando hai bisogno della rappresentazione di stringa di un object non stringa.

  1. Usa quando qualcosa dovrebbe essere sicuramente l’altra cosa.
  2. Usa quando qualcosa potrebbe essere l’altra cosa.
  3. Usalo quando non ti interessa cosa sia ma vuoi solo usare la rappresentazione della stringa disponibile.

Dipende davvero se sai se o è una stringa e cosa vuoi fare con essa. Se il tuo commento significa che o veramente è una stringa, preferirei il diritto (string)o cast – è improbabile che fallisca.

Il più grande vantaggio dell’uso del cast diretto è che quando fallisce, ottieni una InvalidCastException , che ti dice praticamente cosa è andato storto.

Con l’operatore as , se o non è una stringa, s è impostato su null , il che è utile se non si è sicuri e si desidera testare s :

 string s = o as string; if ( s == null ) { // well that's not good! gotoPlanB(); } 

Tuttavia, se non esegui quel test, lo userai più tardi e avrai una NullReferenceException generata. Questi tendono ad essere più comuni e molto più difficili da rintracciare una volta che si verificano in natura, poiché quasi ogni linea dereferenzia una variabile e può lanciarne una. D’altra parte, se stai provando a lanciare su un tipo di valore (qualsiasi primitiva, o struct come DateTime ), devi usare il cast diretto – il as non funzionerà.

Nel caso speciale della conversione in una stringa, ogni object ha un ToString , quindi il tuo terzo metodo potrebbe essere ok se o non è nullo e pensi che il metodo ToString possa fare ciò che vuoi.

Se sai già quale tipo può trasmettere, usa un cast in stile C:

 var o = (string) iKnowThisIsAString; 

Si noti che solo con un cast in stile C è ansible eseguire una coercizione di tipo esplicita.

Se non sai se è il tipo desiderato e lo userai se lo è, usa come parola chiave:

 var s = o as string; if (s != null) return s.Replace("_","-"); //or for early return: if (s==null) return; 

Si noti che come non chiamerà alcun operatore di conversione di tipo. Sarà solo non nullo se l’object non è nullo e in modo nativo del tipo specificato.

Utilizzare ToString () per ottenere una rappresentazione di stringa leggibile da tutti gli oggetti, anche se non è ansible eseguire il cast sulla stringa.

La parola chiave as è valida in asp.net quando si utilizza il metodo FindControl.

 Hyperlink link = this.FindControl("linkid") as Hyperlink; if (link != null) { ... } 

Questo significa che puoi operare sulla variabile tipizzata piuttosto che doverla lanciare da un object come faresti con un cast diretto:

 object linkObj = this.FindControl("linkid"); if (link != null) { Hyperlink link = (Hyperlink)linkObj; } 

Non è una cosa enorme, ma salva le righe di codice e l’assegnazione delle variabili, in più è più leggibile

‘as’ è basato su ‘is’, che è una parola chiave che verifica in fase di esecuzione se l’object è polimorficamente compatibile (in pratica se è ansible eseguire un cast) e restituisce null se il controllo fallisce.

Questi due sono equivalenti:

Utilizzando ‘come’:

 string s = o as string; 

Usare ‘è’:

 if(o is string) s = o; else s = null; 

Al contrario, il cast di stile c viene eseguito anche in fase di esecuzione, ma genera un’eccezione se non è ansible eseguire il cast.

Solo per aggiungere un fatto importante:

La parola chiave “as” funziona solo con i tipi di riferimento. Non puoi fare:

 // I swear i is an int int number = i as int; 

In quei casi devi usare il casting.

2 è utile per trasmettere a un tipo derivato.

Supponiamo che sia un animale:

 b = a as Badger; c = a as Cow; if (b != null) b.EatSnails(); else if (c != null) c.EatGrass(); 

otterrà un nutrito con un minimo di calchi.

“(stringa) o” genererà InvalidCastException in quanto non esiste cast diretto.

“o come stringa” risulterà in s come riferimento null, piuttosto che come un’eccezione generata.

“o.ToString ()” non è un cast di alcun tipo per sé, è un metodo implementato dall’object, e quindi, in un modo o nell’altro, da ogni class in .net che “fa qualcosa” con l’istanza di la class su cui è chiamato e restituisce una stringa.

Non dimenticare che per la conversione in stringa, c’è anche Convert.ToString (someType instanceOfThatType) dove someType è uno di un set di tipi, essenzialmente i tipi di base dei framework.

Secondo gli esperimenti eseguiti su questa pagina: http://www.dotnetguru2.org/sebastienros/index.php/2006/02/24/cast_vs_as

(questa pagina mostra alcuni errori “referrer illegali” a volte, quindi aggiorna semplicemente se lo fa)

La conclusione è che l’operatore “as” è normalmente più veloce di un cast. A volte molte volte più veloce, a volte appena appena più veloce.

Peroni la cosa “come” è anche più leggibile.

Quindi, dal momento che è sia più veloce e “più sicuro” (non genera eccezioni), e forse è più facile da leggere, ti consiglio di usare “come” tutto il tempo.

Tutte le risposte date sono buone, se potessi aggiungere qualcosa: per usare direttamente i metodi e le proprietà della stringa (es. ToLower) non puoi scrivere:

 (string)o.ToLower(); // won't compile 

puoi solo scrivere:

 ((string)o).ToLower(); 

ma potresti scrivere invece:

 (o as string).ToLower(); 

L’opzione as è più leggibile (almeno secondo me).

 string s = o as string; // 2 

È preferibile, in quanto evita la penalizzazione delle prestazioni del doppio lancio.

Sembra che i due siano concettualmente diversi.

Direct Casting

I tipi non devono essere strettamente correlati. È disponibile in tutti i tipi di sapori.

  • Trasmissione implicita / esplicita personalizzata: in genere viene creato un nuovo object.
  • Valore Tipo Implicito: copia senza perdere informazioni.
  • Tipo di valore esplicito: copia e informazioni potrebbero andare perse.
  • Relazione IS-A: modifica il tipo di riferimento, altrimenti genera un’eccezione.
  • Stesso tipo: “Casting is ridundant”.

Sembra che l’object sarà convertito in qualcos’altro.

Operatore AS

I tipi hanno una relazione diretta. Come in:

  • Tipi di riferimento: relazione IS-A Gli oggetti sono sempre gli stessi, solo i riferimenti cambiano.
  • Tipi di valore: copia i tipi di boxe e annullabili.

Sembra che tu gestirai l’object in un modo diverso.

Campioni e IL

  class TypeA { public int value; } class TypeB { public int number; public static explicit operator TypeB(TypeA v) { return new TypeB() { number = v.value }; } } class TypeC : TypeB { } interface IFoo { } class TypeD : TypeA, IFoo { } void Run() { TypeA customTypeA = new TypeD() { value = 10 }; long longValue = long.MaxValue; int intValue = int.MaxValue; // Casting TypeB typeB = (TypeB)customTypeA; // custom explicit casting -- IL: call class ConsoleApp1.Program/TypeB ConsoleApp1.Program/TypeB::op_Explicit(class ConsoleApp1.Program/TypeA) IFoo foo = (IFoo)customTypeA; // is-a reference -- IL: castclass ConsoleApp1.Program/IFoo int loseValue = (int)longValue; // explicit -- IL: conv.i4 long dontLose = intValue; // implict -- IL: conv.i8 // AS int? wraps = intValue as int?; // nullable wrapper -- IL: call instance void valuetype [System.Runtime]System.Nullable`1::.ctor(!0) object o1 = intValue as object; // box -- IL: box [System.Runtime]System.Int32 TypeD d1 = customTypeA as TypeD; // reference conversion -- IL: isinst ConsoleApp1.Program/TypeD IFoo f1 = customTypeA as IFoo; // reference conversion -- IL: isinst ConsoleApp1.Program/IFoo //TypeC d = customTypeA as TypeC; // wouldn't compile } 

Quando si tenta di ottenere la rappresentazione di stringa di qualsiasi cosa (di qualsiasi tipo) che potrebbe potenzialmente essere nullo, preferisco la riga di codice sottostante. È compatto, richiama ToString () e gestisce correttamente i valori null. Se o è nullo, s contiene String.Empty.

 String s = String.Concat(o); 

Poiché nessuno lo ha menzionato, il più vicino a instanceOf to Java per parola chiave è questo:

 obj.GetType().IsInstanceOfType(otherObj) 

Usa la string s = (string) o; cast diretta string s = (string) o; se nel contesto logico della string dell’app è l’unico tipo valido. Con questo approccio, riceverai InvalidCastException e implementerai il principio di Fail-fast . La tua logica sarà protetta dal passare il tipo non valido ulteriormente o ottenere NullReferenceException se usato as operatore.

Se la logica prevede diversi tipi di cast string s = o as string; e controllare su null o utilizzare is operatore.

Nuove funzioni interessanti sono apparse in C # 7.0 per semplificare il cast e il check è un Pattern matching :

 if(o is string s) { // Use string variable s } or switch (o) { case int i: // Use int variable i break; case string s: // Use string variable s break; } 

Le seguenti due forms di conversione del tipo (casting) sono supportate in C #:

|

(CV

• Converti il ​​tipo statico di v in c nell’espressione specificata

• Possibile solo se il tipo dinamico di v è c, o un sottotipo di c

• In caso contrario, viene generata una InvalidCastException

|

v come C

• Variante non fatale di (c) v

• Pertanto, convertire il tipo statico di v in c nell’espressione specificata

• Restituisce null se il tipo dinamico di v non è c, o un sottotipo di c