Domanda

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 (ok, il terzo non è un casting, ma ottieni l'intento). Quale dovrebbe essere preferito?

È stato utile?

Soluzione

string s = (string)o; // 1

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

string s = o as string; // 2

Assegna null a s se o non è una stringa o se o è null . Per questo motivo, non è possibile utilizzarlo con tipi di valore (l'operatore non potrebbe mai restituire null in quel caso). Altrimenti, assegna o a s .

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

Provoca NullReferenceException if o è null . Assegna qualunque o.ToString () ritorni su s , indipendentemente dal tipo o .


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

3 non è un cast ed è solo una chiamata al metodo. Usalo per quando hai bisogno della rappresentazione in forma di stringa di un oggetto non stringa.

Altri suggerimenti

  1. string s = (string) o; Usa quando qualcosa dovrebbe sicuramente sia l'altra cosa.
  2. string s = o as string; Usa quando qualcosa potrebbe essere l'altro cosa.
  3. string s = o.ToString (); Utilizza quando non ti importa cosa lo è ma vuoi solo usare il rappresentazione stringa disponibile.

Dipende davvero dal fatto che tu sappia se o è una stringa e cosa vuoi farci. Se il tuo commento significa che o è davvero una stringa, preferirei il cast dritto (stringa) o - è improbabile che fallisca.

Il più grande vantaggio dell'utilizzo del cast diretto è che quando fallisce, si ottiene un InvalidCastException , che ti dice praticamente cosa è andato storto.

Con l'operatore as , se o non è una stringa, s è impostato su null , 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, utilizzerai s in seguito e avrai un NullReferenceException generata. Questi tendono ad essere più comuni e un lotto più difficile da rintracciare una volta che si verificano in natura, poiché quasi ogni riga dereferenzia una variabile e può lanciarne una. D'altra parte, se si sta tentando di eseguire il cast su un tipo di valore (qualsiasi primitiva o strutture come DateTime ), devi usare il cast diretto - come non funzionerà.

Nel caso speciale della conversione in una stringa, ogni oggetto ha un ToString , quindi il tuo terzo metodo potrebbe andare bene se o non è nullo e pensi che il Il metodo ToString potrebbe fare quello che vuoi.

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

var o = (string) iKnowThisIsAString; 

Nota che solo con un cast in stile C puoi eseguire la coercizione esplicita del tipo.

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;

Nota che come non chiamerà alcun operatore di conversione di tipo. Sarà non nullo solo se l'oggetto non è nullo e nativamente del tipo specificato.

Usa ToString () per ottenere una rappresentazione di stringa leggibile dall'uomo di qualsiasi oggetto, anche se non può essere trasmesso a stringa.

La parola chiave as è buona 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 digitata piuttosto che doverla lanciare da oggetto come faresti con un cast diretto:

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

Non è una cosa enorme, ma salva righe di codice e assegnazione di variabili, inoltre è più leggibile

'as' si basa su 'is', che è una parola chiave che verifica in fase di esecuzione se l'oggetto è polimorphycally compatibile (fondamentalmente se è possibile eseguire un cast) e restituisce null se il controllo fallisce.

Questi due sono equivalenti:

Uso di 'as':

string s = o as string;

Usando 'is':

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

Al contrario, il cast in stile c è realizzato anche in fase di esecuzione, ma genera un'eccezione se il cast non può essere creato.

Solo per aggiungere un fatto importante:

La parola chiave 'as' funziona solo con tipi di riferimento. Non puoi fare:

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

In questi casi devi usare il casting.

2 è utile per il cast su un tipo derivato.

Supponi che a sia un animale:

b = a as Badger;
c = a as Cow;

if (b != null)
   b.EatSnails();
else if (c != null)
   c.EatGrass();

riceverà un alimentato con un minimo di cast.

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

(questa pagina presenta alcuni errori di "riferimento illegale" a volte, quindi aggiorna se lo fa)

La conclusione è, il "come" l'operatore è normalmente più veloce di un cast. A volte molto più veloce, a volte appena più veloce.

I peronsonalmente cosa " come " è anche più leggibile.

Quindi, poiché è sia più veloce che "più sicuro" (non genererà eccezioni), e forse più facile da leggere, ti consiglio di utilizzare " as " tutto il tempo.

pollici (stringa) o " si tradurrà in una InvalidCastException in quanto non esiste un cast diretto.

" o come stringa " si tradurrà in un riferimento null, anziché in un'eccezione.

" o.ToString () " non è un cast di alcun tipo di per sé, è un metodo implementato dall'oggetto, e quindi in un modo o nell'altro, da ogni classe in .net che "fa qualcosa" con l'istanza della classe viene chiamato e restituisce una stringa.

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

Tutte le risposte fornite sono buone, se potessi aggiungere qualcosa: Per utilizzare direttamente i metodi e le proprietà della stringa (ad es. ToLower) non puoi scrivere:

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

puoi solo scrivere:

((string)o).ToLower();

ma invece potresti scrivere:

(o as string).ToLower();

L'opzione as è più leggibile (almeno secondo la mia opinione).

string s = o as string; // 2

È preferito, poiché evita la penalità prestazionale del doppio casting.

Sembra che entrambi siano concettualmente diversi.

Casting diretto

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

  • Cast implicito / esplicito personalizzato: di solito viene creato un nuovo oggetto.
  • Tipo di valore 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 ridondante'.

Sembra che l'oggetto verrà 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, cambiano solo i riferimenti.
  • Tipi di valore: Copia boxe e tipi annullabili.

Sembra che tu gestisca l'oggetto in modo diverso.

Esempi 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<int32>::.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
    }

Vorrei attirare l'attenzione sui seguenti aspetti specifici dell'operatore come :

https://docs.microsoft.com / it-it / dotnet / csharp / lingua-reference / parole chiave / come

  

Tieni presente che l'operatore as esegue solo conversioni di riferimento,   conversioni nullable e conversioni di boxe. L'operatore as non può   eseguire altre conversioni, come conversioni definite dall'utente, che   dovrebbe invece essere eseguito usando le espressioni cast.

Quando cerco di ottenere la rappresentazione in formato stringa di qualsiasi cosa (di qualsiasi tipo) che potrebbe essere potenzialmente nulla, preferisco la riga di codice in basso. È compatto, invoca ToString () e gestisce correttamente i null. Se o è null, s conterrà String.Empty.

String s = String.Concat(o);

Dato che nessuno l'ha menzionato, il più vicino a instanceOf a Java per parola chiave è questo:

obj.GetType().IsInstanceOfType(otherObj)

Usa il cast diretto string s = (string) o; se nel contesto logico della tua app string è l'unico tipo valido. Con questo approccio otterrai InvalidCastException e implementerai il principio di Fail- veloce. La tua logica sarà protetta dal passaggio ulteriore del tipo non valido o riceverà NullReferenceException se utilizzato come .

Se la logica prevede diversi tipi diversi cast stringa s = o come stringa; e controllalo su null o usa è operatore

Sono state introdotte nuove funzionalità interessanti in C # 7.0 per semplificare il cast e verificare che sia Corrispondenza del modello :

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 forme di conversione del tipo (casting) sono supportate in C #:

|

(C) v

& # 8226; Converti il ??tipo statico di v in c nell'espressione data

& # 8226; Possibile solo se il tipo dinamico di v è c o un sottotipo di c

& # 8226; In caso contrario, viene generata una InvalidCastException

|

v come C

& # 8226; Variante non fatale di (c) v

& # 8226; Quindi, converti il ??tipo statico di v in c nell'espressione data

& # 8226; Restituisce null se il tipo dinamico di v non è c o un sottotipo di c

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top