myCSharp.de - DIE C# und .NET Community
Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 
 | Suche | FAQ

» Hauptmenü
myCSharp.de
» Startseite
» Forum
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Suche
» Regeln
» Wie poste ich richtig?
» Forum-FAQ

Mitglieder
» Liste / Suche
» Wer ist wo online?

Ressourcen
» openbook: Visual C#
» openbook: OO
» Microsoft Docs

Team
» Kontakt
» Übersicht
» Wir über uns

» myCSharp.de Diskussionsforum
Du befindest Dich hier: Community-Index » Diskussionsforum » Knowledge Base » FAQ » [FAQ] Casten aber richtig: Boxing/Unboxing - () / is / as / Pattern Matching
Letzter Beitrag | Erster ungelesener Beitrag Druckvorschau | Thema zu Favoriten hinzufügen

Antwort erstellen
Zum Ende der Seite springen  

[FAQ] Casten aber richtig: Boxing/Unboxing - () / is / as / Pattern Matching

 
Autor
Beitrag « Vorheriges Thema | Nächstes Thema »
Programmierhans
myCSharp.de-Poweruser/ Experte

avatar-1651.gif


Dabei seit: 05.04.2005
Beiträge: 4.221
Entwicklungsumgebung: VS2003-VS2013 / SAP WebIDE
Herkunft: Zentralschweiz


Programmierhans ist offline

[FAQ] Casten aber richtig: Boxing/Unboxing - () / is / as / Pattern Matching

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Kurz und bündig zusammengefasst die verschiedenen Varianten von einem Type in einen anderen zu casten.

Es gibt verschiedene Varianten:

Direct-Cast:
-Harter Cast kann InvalidCastException auslösen wenn der Type nicht passt:
-Zugriff auf die Zielvariable darf erst nach einer Prüfung auf null stattfinden (c könnte ja null sein)

As-Cast:
-Weicher Cast mit Typenabfrage: Löst keine InvalidCastException aus wenn der Type nicht passt.
-Zugriff auf die Zielvariable darf erst nach einer Prüfung auf null stattfinden (c könnte ja null sein)

Sichere Varianten

mittels is:
-Prüfung auf korrekten Typen (null is TextBox ergibt = false)
-Zugriff auf die Zielvariable sofort möglich

mittels as:
-Prüfung auf null und auf korrekten Typen
-Zugriff auf die Zielvariable sofort möglich
-Insgesamt weniger Effizient als die is-Variante
[Edit]
-spart den is-Zugriff
[/Edit]

C#-Code:
foreach (Control c in this.Controls)
{
    //Direct-Cast (es kracht wenn c nicht TextBox ist):
    // und es kracht beim Zugriff auf tDirect wenn c null ist.
    TextBox tDirect=(TextBox)c;

    //As-Cast es kracht beim Zugriff auf tAS wenn c null ist oder c keine Textbox ist (dann ist tAs auch null).
    TextBox tAs=c as TextBox;

    //der As-Cast macht intern so was:
    //es kracht beim Zugriff auf tAS wenn c null ist.
    TextBox tIs=c is TextBox?(TextBox)c:null;


    //und so ist die sichere Variante mit is:
    if(c is TextBox)
    {
        TextBox tSave=(TextBox)c;
        //so ist tSave sicher nie null
    }

    //und so eine sichere Variante mit as
    TextBox tAsSave=c as TextBox;
    if (tAsSave!=null)
    {
        //so ist tAsSave sicher nie null
    }
}

Edit: Is-Variante gekürzt:
22.11.2006 20:25 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Zwischen diesen beiden Beiträgen liegen mehr als 13 Jahre.
Abt
myCSharp.de-Team

avatar-4119.png


Dabei seit: 20.07.2008
Beiträge: 14.520
Herkunft: BW


Abt ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Nach fast 14 Jahren des initialen Beitrags hat sich in C# doch einiges geändert.

Boxing und Unboxing

Boxing ist die Art und Weise wie mit Typen in C# umgegangen wird.
Die Konvertierung von einem konkreten Value-Type (zB int) in den Typ object nennt sich Boxing.

C#-Code:
int i = 123;
// boxing von i auf o
object o = i;

Das Gegenteil von Boxing ist das Unboxing; hier erfolgt die Konvertierung von object auf den jeweiligen Value-Type.

C#-Code:
object o = 123;
int i = (int)o;  // unboxing

Achtung: Beim Unboxing muss beachtet werden, dass der ursprüngliche Value-Type verwendet wird, ansonsten quittiert das die Runtime mit einer InvalidCastException.

C#-Code:
// Funktioniert:
int i1 = 123;
object o = i1;
int i2 = (int)o;

// InvalidCastException:
int i1 = 123;
object o = i1;
uint i2 = (uint)o; // der Ursprung ist int und nicht uint!

Mehr Informationen in der Dokumentation von  Boxing und Unboxing.

Unsicheres Casten aka hartes Konvertieren

Das unsichere Konvertieren wirft eine InvalidCastException, wenn der Ziel-Type nicht passt.

C#-Code:
object o = "Hallo";
string s = (string)o; // funktioniert
int wert = (int)o; // InvalidCastException

Sicheres Casten mit dem as-Operator

Aufgrund der potentiellen InvalidCastException gab es seit Beginn von C# auch den as-Operator, mit dem ein sicheres Konvertieren möglich ist - allerdings nur für Referenztypen.

Sofern der Type nicht identisch ist wird keine Exception geworfen, sondern null gesetzt.

C#-Code:
object s = "Hallo";
MyClass myClassInstance = s as MyClass;

if (myClassInstance == null)
{
    // Konvertierung fehlgeschlagen
}
else
{
    // Konvertierung war erfolgreich
}

Mehr Informationen in der Dokumentation von  as-Operator.

Sicheres Casten mit dem is-Operator

Der as-Operator funktioniert nur mit Referenztypen; daher nicht mit int und Co. Die Alternative an dieser Stelle ist der is-Operator.

Mit dem is-Operator kann vor dem Konvertieren geprüft werden, ob der Typ passt:

C#-Code:
int wert;
if (s is int)
{
     wert = (int)s;
}
else
{
    // Es kann nicht konvertiert werden, weil s kein int ist.
}

Der is-Operator kann mit Wert- und Referenztypen verwendet werden.

Mehr Informationen in der Dokumentation von  is-Operator.

Pattern Matching mit is - Type Pattern

Mit C# 7 wurde das Pattern Matching eingeführt. Pattern Matching fällt unter die Kategorie Syntaxzucker und verkürzt die Schreibweise.
Im Falle des Pattern Matching mit dem is-Operator kann dabei die Prüfung und das Casting in einen Befehl verkürzt werden.

C#-Code:
// Ohne Pattern Matching:
Person p1 = new Person();
object o = p1;

Person p2;
if (o is Person)
{
    p2 = (Person)o;

   // p2 ist nun eine Instanz von Person
}

// Mit Pattern Matching:
Person p1 = new Person();
object o = p1;

if (o is Person p2)
{
   // p2 ist nun eine Instanz von Person
}

Das Pattern Matching an dieser Stelle funktioniert auch mit var:

C#-Code:
    Person p1 = new Person();
    object o = p1;

    if (o is var v)
    {
        Console.WriteLine($"var ist vom Typ: {v.GetType().Name}"); // Ausgabe: var ist vom Typ: Person
    }

Achtung: aus Compiler-Sicht ist var vom Typ object; damit stehen die Eigenschaften nur zur Laufzeit zur Verfügung!

Mehr Informationen in der Dokumentation von  Type Testing mit Pattern Matching.

Operatoren

Die Umwandlung von int in uint ist streng genommen keine Konvertierung, sondern eine Umwandlung; im Englischen als reassigment bezeichnet.
Dass im Sprachgebrauch von C# trotzdem damit umgegangen werden kann als sei es eine Konvertierung, können Operatoren verwendet werden.
Ein solcher explziter Operator ist in diesem Fall für die Umwandlung von int in uint verantwortlich:

C#-Code:
public static explicit operator int(uint value) => Convert.ToInt32(value);

C#-Code:
int i = 1;
uint u = (uint)i; // die harte Umwandlung mit (int) stellt die explizite Konvertierung dar

Neben der expliziten Konvertierung, die das Voranstellen des Zieltyps erfordert, gibt es auch die implizite Konvertierung.

Hierbei erkennt der Compiler automatisch den entsprechenden Operator, um die Konvertierung durchzuführen. Ist kein Operator deklariert wird ein Compiler-Error generiert, der beklagt, dass nur eine explizite und keine implizite Konvertierung gefunden wurde.

C#-Code:
public class MyCustomInteger
{
    public int Value { get; }

    public MyCustomInteger(int value)
    {
        Value = value;
    }

    public static explicit operator MyCustomInteger(int value) => new MyCustomInteger(value);
    // Verwendung:
    MyCustomInteger myValue = (MyCustomInteger)1;

    // oder

    public static implicit operator MyCustomInteger(int value) => new MyCustomInteger(value);
    // Verwendung:
    MyCustomInteger myValue = 1;
}

Achtung: es können nicht beide Operator-Arten mit den gleichen Parameter gleichzeitig deklariert werden.

Mehr Informationen in der Dokumentation von  Benutzerdefinierte Konvertierungsoperatoren.
10.10.2020 13:43 Beiträge des Benutzers | zu Buddylist hinzufügen
Baumstruktur | Brettstruktur       | Top 
myCSharp.de | Forum Der Startbeitrag ist älter als 14 Jahre.
Der letzte Beitrag ist älter als 3 Monate.
Antwort erstellen


© Copyright 2003-2021 myCSharp.de-Team | Impressum | Datenschutz | Alle Rechte vorbehalten. | Dieses Portal verwendet zum korrekten Betrieb Cookies. 28.01.2021 10:48