it-swarm.com.de

Direktes Casting gegen 'als' Operator?

Betrachten Sie den folgenden Code:

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
}

Was ist der Unterschied zwischen den drei Arten von Casting (okay, das dritte ist kein Casting, aber Sie haben die Absicht). Welches sollte man bevorzugen?

665
nullDev
string s = (string)o; // 1

Löst InvalidCastException aus, wenn o kein string ist. Andernfalls wird o zu s zugewiesen, auch wenn onull ist.

string s = o as string; // 2

Weist nulls zu, wenn o kein string ist oder wenn onull ist. Aus diesem Grund können Sie es nicht mit Werttypen verwenden (der Operator könnte in diesem Fall niemals null zurückgeben). Andernfalls wird o zu s zugewiesen.

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

Verursacht eine NullReferenceException wenn onull ist. Weist zu, was o.ToString() zu s zurückgibt, unabhängig vom Typ o.


Verwenden Sie 1 für die meisten Konvertierungen - es ist einfach und unkompliziert. Ich neige dazu, fast nie 2 zu verwenden, da ich normalerweise eine Ausnahme erwarte, wenn etwas nicht der richtige Typ ist. Ich habe nur einen Bedarf für diese Funktion vom Typ "return-null" mit schlecht gestalteten Bibliotheken gesehen, die Fehlercodes verwenden (z. B. "return null = error" anstelle von Ausnahmen).

3 ist keine Besetzung und nur ein Methodenaufruf. Verwenden Sie diese Option, wenn Sie die Zeichenfolgendarstellung eines Nichtzeichenfolgenobjekts benötigen.

791
Sander
  1. string s = (string)o; Verwenden, wenn etwas definitiv das andere sein soll.
  2. string s = o as string; Verwenden Sie, wenn etwas könnte sein die andere Sache.
  3. string s = o.ToString(); Verwenden Sie diese Option, wenn es Ihnen egal ist, was es ist, Sie aber nur die verfügbare Zeichenfolgendarstellung verwenden möchten.
332
Quibblesome

Es hängt wirklich davon ab, ob Sie wissen, ob o eine Zeichenfolge ist und was Sie damit tun möchten. Wenn Ihr Kommentar bedeutet, dass o wirklich eine Zeichenfolge ist, würde ich die direkte (string)o - Umwandlung bevorzugen - es ist unwahrscheinlich, dass dies fehlschlägt.

Der größte Vorteil der Verwendung des Straight Cast ist, dass Sie bei einem Fehlschlag eine InvalidCastException erhalten, die Ihnen ziemlich genau sagt, was schief gelaufen ist.

Mit dem Operator as wird o auf s gesetzt, wenn null keine Zeichenfolge ist. Dies ist praktisch, wenn Sie sich nicht sicher sind und dies möchten Test s:

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

Wenn Sie diesen Test jedoch nicht durchführen, verwenden Sie s später und lassen eine NullReferenceException auslösen. Diese sind in der Regel häufiger und eine Menge schwerer aufzuspüren, wenn sie in freier Wildbahn vorkommen, da fast jede Zeile eine Variable dereferenziert und möglicherweise eine wirft . Wenn Sie dagegen versuchen, einen Wertetyp (ein beliebiges Grundelement oder Strukturen wie DateTime ) zu konvertieren, müssen Sie die direkte Konvertierung verwenden: as won funktioniert nicht.

In dem speziellen Fall der Konvertierung in einen String hat jedes Objekt eine ToString, daher ist Ihre dritte Methode möglicherweise in Ordnung, wenn o nicht null ist und Sie denken, die ToString -Methode könnte machen was du willst.

29
Blair Conrad

Wenn Sie bereits wissen, zu welchem ​​Typ die Umwandlung erfolgen kann, verwenden Sie eine Umwandlung im C-Stil:

var o = (string) iKnowThisIsAString; 

Beachten Sie, dass Sie nur mit einer C-Besetzung einen expliziten Typenzwang ausführen können.

Wenn Sie nicht wissen, ob es sich um den gewünschten Typ handelt, und wenn dies der Fall ist, verwenden Sie als Schlüsselwort:

var s = o as string;
if (s != null) return s.Replace("_","-");

//or for early return:
if (s==null) return;

Beachten Sie, dass as keine Typkonvertierungsoperatoren aufruft. Sie ist nur dann ungleich Null, wenn das Objekt nicht Null ist und vom angegebenen Typ ist.

Verwenden Sie ToString (), um eine lesbare Zeichenfolgendarstellung eines Objekts abzurufen, auch wenn es nicht in eine Zeichenfolge umgewandelt werden kann.

9
Mark Cidade

Das Schlüsselwort as ist in asp.net sinnvoll, wenn Sie die FindControl-Methode verwenden.

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

Dies bedeutet, dass Sie die typisierte Variable bearbeiten können, anstatt sie wie bei einer direkten Umwandlung aus object umwandeln zu müssen:

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

Es ist keine große Sache, aber es spart Codezeilen und die Zuweisung von Variablen und es ist besser lesbar

7
Glenn Slaven

'as' basiert auf 'is', einem Schlüsselwort, das zur Laufzeit prüft, ob das Objekt polimorph kompatibel ist (im Grunde genommen, ob eine Umwandlung möglich ist) und null zurückgibt, wenn die Prüfung fehlschlägt.

Diese beiden sind gleichwertig:

'As' verwenden:

string s = o as string;

'Is' verwenden:

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

Im Gegenteil, die C-Besetzung wird auch zur Laufzeit erstellt, löst jedoch eine Ausnahme aus, wenn die Besetzung nicht möglich ist.

Nur um eine wichtige Tatsache hinzuzufügen:

Das Schlüsselwort 'as' funktioniert nur mit Referenztypen. Du kannst nicht tun:

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

In diesen Fällen müssen Sie Casting verwenden.

6
Sergio Acosta

2 eignet sich zum Umwandeln in einen abgeleiteten Typ.

Angenommen a ist ein Tier:

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

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

wird a mit einem Minimum an Würfen gefüttert.

5
Joel in Gö

"(string) o" führt zu einer InvalidCastException, da keine direkte Umwandlung erfolgt.

"o as string" führt dazu, dass s eine Nullreferenz ist und keine Ausnahme ausgelöst wird.

"o.ToString ()" ist keine Art von Besetzung per se, sondern eine Methode, die vom Objekt und somit auf die eine oder andere Weise von jeder Klasse in .net implementiert wird, die mit der Instanz von "etwas tut" Die Klasse, für die sie aufgerufen wurde, gibt eine Zeichenfolge zurück.

Vergessen Sie nicht, dass es für die Konvertierung in einen String auch Convert.ToString (someType instanceOfThatType) gibt, wobei someType einer von mehreren Typen ist, im Wesentlichen die Framework-Basistypen.

4
Rob

Nach den auf dieser Seite durchgeführten Experimenten: http://www.dotnetguru2.org/sebastienros/index.php/2006/02/24/cast_vs_as

(Auf dieser Seite werden manchmal "illegale Referrer" -Fehler angezeigt. Aktualisieren Sie die Seite, wenn dies der Fall ist.)

Fazit: Der Operator "as" ist normalerweise schneller als ein Cast. Manchmal um ein Vielfaches schneller, manchmal nur kaum schneller.

Ich persönlich Ding "als" ist auch besser lesbar.

Da es sowohl schneller als auch "sicherer" (keine Ausnahme) und möglicherweise einfacher zu lesen ist, empfehle ich, "as" die ganze Zeit zu verwenden.

4
Brady Moritz
string s = o as string; // 2

Bevorzugt wird, da es den Performance-Nachteil des Doppelcastings vermeidet.

3
Chris S

Alle gegebenen Antworten sind gut, wenn ich etwas hinzufügen darf: Um die Methoden und Eigenschaften von Strings (z. B. ToLower) direkt zu verwenden, können Sie nicht schreiben:

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

du kannst nur schreiben:

((string)o).ToLower();

aber du könntest stattdessen schreiben:

(o as string).ToLower();

Die Option as ist besser lesbar (zumindest meiner Meinung nach).

3
BornToCode

Es scheint, dass die beiden konzeptionell unterschiedlich sind.

Direct Casting

Typen müssen nicht eng miteinander verwandt sein. Es kommt in allen Arten von Aromen.

  • Benutzerdefiniertes implizites/explizites Casting: Normalerweise wird ein neues Objekt erstellt.
  • Werttyp Implizit: Kopieren ohne Informationsverlust.
  • Werttyp explizit: Kopie und Informationen können verloren gehen.
  • IS-A-Beziehung: Referenztyp ändern, sonst wird eine Ausnahme ausgelöst.
  • Gleicher Typ: 'Casting ist überflüssig'.

Es fühlt sich an, als würde das Objekt in etwas anderes umgewandelt.

AS-Operator

Typen haben eine direkte Beziehung. Wie in:

  • Referenztypen: IS-A-Beziehung Objekte sind immer gleich, nur die Referenz ändert sich.
  • Werttypen: Kopie Boxing- und Nullable-Typen.

Es fühlt sich so an, als würden Sie das Objekt auf eine andere Art und Weise behandeln.

Proben und 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
    }
3
Lucas Teixeira

Ich möchte auf die folgenden Besonderheiten des Operators als aufmerksam machen:

https://docs.Microsoft.com/en-us/dotnet/csharp/language-reference/keywords/as

Beachten Sie, dass der Operator as nur Referenzkonvertierungen, nullfähige Konvertierungen und Boxing-Konvertierungen ausführt. Der as-Operator kann keine anderen Konvertierungen durchführen, z. B. benutzerdefinierte Konvertierungen, die stattdessen mithilfe von Besetzungsausdrücken durchgeführt werden sollten.

2
Vadim S.

Verwenden Sie die direkte Umwandlung string s = (string) o;, wenn im logischen Kontext Ihrer App string der einzig gültige Typ ist. Mit diesem Ansatz erhalten Sie InvalidCastException und implementieren das Prinzip von Fail-Fast . Ihre Logik wird davor geschützt, den ungültigen Typ weiterzugeben oder NullReferenceException zu erhalten, wenn der Operator as verwendet wird.

Wenn die Logik mehrere unterschiedliche Typen erwartet, wird string s = o as string; und überprüfe es auf null oder benutze den is Operator.

In C # 7.0 wurde eine neue coole Funktion eingeführt, um die Umwandlung zu vereinfachen und zu überprüfen, ob es sich um einen Mustervergleich handelt :

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;
 }
0
Dmitry

Da dies von niemandem erwähnt wurde, ist die Instanz von Java per Schlüsselwort am nächsten:

obj.GetType().IsInstanceOfType(otherObj)
0
Bennett Yeo

Wenn ich versuche, die Zeichenfolgendarstellung von allem (von jedem Typ) abzurufen, der möglicherweise null sein könnte, bevorzuge ich die folgende Codezeile. Es ist kompakt, ruft ToString () auf und verarbeitet Nullen korrekt. Wenn o null ist, enthält s String.Empty.

String s = String.Concat(o);
0
xtrem

Die folgenden zwei Formen der Typkonvertierung (Casting) werden in C # unterstützt:

|

(C) v

• Konvertieren Sie den statischen Typ von v in c im angegebenen Ausdruck

• Nur möglich, wenn der dynamische Typ von v c oder ein Untertyp von c ist

• Wenn nicht, wird eine InvalidCastException ausgelöst

|

v als C

• Nicht tödliche Variante von (c) v

• Konvertieren Sie daher den statischen Typ von v in c im angegebenen Ausdruck

• Gibt null zurück, wenn der dynamische Typ von v nicht c oder ein Untertyp von c ist

0
user4931677