TryCast richtig verstehen?

  • VB.NET

Es gibt 12 Antworten in diesem Thema. Der letzte Beitrag () ist von ErfinderDesRades.

    TryCast richtig verstehen?

    Hallo Leute,

    ich hätte mal eine Grundlagenfrage zur Anwendung von TryCast.

    Also wie in msdn beschrieben ist mir schon klar: Leitet eine Typkonvertierungsoperation ein, die keine Ausnahme auslöst.
    (TryCast gibt Nothing (Visual Basic) zurück, sodass Sie keine Ausnahme behandeln, sondern nur das zurückgegebene Ergebnis mit Nothing testen müssen.)
    Wenn also CType oder DirectCast eine (InvalidCastException) werfen würde.

    Probleme habe ich mit TryCast auf Objekte anzuwenden bzw. zu verstehen. Sorry!!

    z.B.

    VB.NET-Quellcode

    1. Dim rdb1 As RadioButton = TryCast(UserControl.FindControl("rdb1"), RadioButton)


    Hier hole ich mir den Zustand eines Radiobutton von einer .ascx Datei in eine . aspx Datei. (funktioniert auch, ich will es nur richtig verstehen, was hier genau passiert )
    Warum brauch ich hier TryCast?
    Warum funktioniert dies nicht wenn ich den Code anwende um den Zustand eines Steuerelements von .ascx Datei in einer andere .ascx Datei abrufen möchte.

    Oder hier ein kongretes Problem!

    VB.NET-Quellcode

    1. Dim p As Panel = TryCast(FindControl("pAdresse"), Panel)
    2. Dim r As Repeater = TryCast(FindControl("rptAdresse"), Repeater)
    3. Try
    4. Dim ph As PlaceHolder = TryCast(r.Controls(cnt).FindControl("phAdresse"), PlaceHolder)
    5. Dim txtName As TextBox = TryCast(ph.Controls(0).FindControl("txtName"), TextBox)
    6. Catch ex As Exception
    7. Exit Do
    8. End Try


    Wie Ihr seht sind hier einige TryCast vorhanden.
    Also es geht mir hier nicht um eine Codelösung sondern um eine Verständnis-frage
    wann und warum ich TryCatch verwenden muss.

    Bin euch für jede Antwort sehr Dankbar!!
    Verglichen werden folgende Operationen:

    DirectCast
    Leitet eine Typkonvertierungsoperation ein, die auf Vererbung oder Implementierung beruht.
    TryCast
    Leitet eine Typkonvertierungsoperation ein, die keine Ausnahme auslöst. Stattdessen wird die Zielvariable auf Nothing gesetzt.
    CType
    Gibt das Ergebnis der expliziten Konvertierung eines Ausdrucks in einen angegebenen Datentyp, ein Objekt, eine Struktur, eine Klasse oder eine Schnittstelle zurück.


    Zeitmessung

    Jede Variante wurde mit jeweils 1000 Testdurchläufen getestet.

    Typumwandlung via

    DirectCast

    Zeit ohne Fehler: 0.0019 ms
    Zeit mit Fehler: 2956.5607 ms

    TryCast
    Zeit ohne Fehler: 0.0029 ms
    Zeit mit Fehler: 0.0056 ms


    CType
    Zeit ohne Fehler: 0.0019 ms
    Zeit mit Fehler: 2897.9826 ms

    Ergebnis

    DirectCast
    Im Fehlerfall am langsamsten, da die Exception gecatcht werden muss und dies viel Zeit kostet. Im fehlerfreien Fall minimal schneller als TryCast.

    TryCast
    Im Fehlerfall deutlich am schnellsten. Im fehlerfreien Fall dauert es länger als CType und DirectCast, da intern mehr gemacht wird, um im Fehlerfall ein Nothing liefern zu können (siehe Beschreibung).

    CType
    Im Fehlerfall wie DirectCast. Im fehlerfreien Fall genauso schnell wie DirectCast, allerdings kann eine explizite Konvertierung vorgenommen werden, welche erhebliche Performance Einbußen hat.

    Fazit

    Es sollte möglichst immer DirectCast vorgezogen werden (egal ob ValueType oder ReferenceType). Wenn die Möglichkeit besteht, dass eine bekannte, unterschiedliche Menge an Zieltypen möglich ist(z. B. durch Vererbung) oder dass das Quellobject Nothing ist, dann sollte TryCast verwendet werden (was impliziert, dass danach auf Nothing) geprüft weden muss. CType ist in den seltensten fällen sinnvoll, da rein aus Typsicherheitsgründen eine explizite Konvertieurng vorgenommen werden sollte. Die Kürzel CStr, CInt, ... sind natürlich erlaubt da sie kürzer sind als DirectCast(source, Integer). Allerdings muss man hier aufpassen, dass auch hier eine Konvertierung à la CType stattfinden kann (z. B. String nach Integer, wenn der String Zahlen enthält). Das sollte vermieden werden.


    Das ist ein Auszug aus einem Internen Wiki-Artikel, den ich vor einiger Zeit verfasst habe.
    Vielleicht hilft dir dies weiter. Vor allem, da du im Moment alles mit TryCast versuchst.

    Vorerst vielen Dank Kagurame!

    Sind schon mal gute Informationen, trotzdem verstehe ich es immer noch nicht ganz.
    Warum brauch ich in diesem Fall überhaupt eine Typkonvertierung mit TryCast?
    rdb1 ist doch schon ein RadioButton, warum muss ich in nochmals Casten, das versteh ich nicht ganz?

    VB.NET-Quellcode

    1. Dim rdb1 As RadioButton = TryCast(UserControl.FindControl("rdb1"), RadioButton)
    Ich vermute mal du brauchst es, weil dir FindControl ein Element vom Typ Control zurück liefert. Vermute ich mal...

    Und DirectCast kannst du hier ja auch verwenden...

    Wenn du TryCast benutzt, nimm auf jeden Fall den Try Catch ausenrum weg, weil der wird ja dadurch unnötig.

    Kagurame schrieb:

    Wenn die Möglichkeit besteht, dass eine bekannte, unterschiedliche Menge an Zieltypen möglich ist(z. B. durch Vererbung) oder dass das Quellobject Nothing ist, dann sollte TryCast verwendet werden (was impliziert, dass danach auf Nothing) geprüft weden muss.

    Deine Vermutung ist richtig!

    Nur zur Information der Code ist nicht von mir, sondern von einen Kollegen!
    Ich versuche nur zu verstehen was er da gemacht hat.

    Ich habe jetzt folgendes versucht:

    VB.NET-Quellcode

    1. Dim rdb1 As RadioButton = UserControl.FindControl("rdb1")


    und es funktioniert auch, dass heiß ich brauch in diesem Fall gar kein Cast, warum wurde dann ein TryCast verwendet

    (Ahhh!!! Sorry, ich steh so was auf der Leitung und komm nicht runter ?(
    Achja fragen kann ich ihn leider nicht.

    VBuchner schrieb:

    und es funktioniert auch

    Schalte ein: Option Strict On
    und dann funzt es nicht mehr. Was du mit dem Code machst, nennt sich IMPLIZITE Konvertierung (führt ebenfalls einen Cast aus, allerdings wird das vom compiler automatisch gemacht). TryCast, CType etc sind hingegen EXPLIZITE Konvertierungen. EXPLIZIT heißt, dass der Programmierer GENAU sagen muss, was er WILL. Das verhindert, dass man etwas unglaublich blödes tut (i as Integer = "1") und der Automatismus von VB diese Blödheit verschleiert, was irgendwann später dann zu einem Problem werden kann.
    Wenn es verwendet wurde, aber nicht gebraucht wurde... dann zwei Möglichkeiten: der Kollege schreibt gern Sinnlosen Code (wie das Try Catch um ein TryCast drum rum) oder der Kollege ist von was anderem ausgegangen...
    Oder du verwendest kein

    VB.NET-Quellcode

    1. Option Strict On


    bau das noch ein...
    BTW:

    1. Explizit: Peter ist klein
    2. Implizit: Peter ist nicht sehr groß (DAS "impliziert" dann, dass er wohl eher klein sein müsste)

    Das 1 ist nie ein Problem (außer ggf für Peter). Das 2. KANN ein Problem sein: "Peter ist nicht sehr groß, er ist RIESENGROSS". Der implizite Schluss ist nämlich nicht zwangsläufig eindeutig. Und wenn man (jetzt wieder Programmieren) VB die "Entscheidung" überläßt, was "gemeint" war/ist, dann kann sich der Compiler auch mal irren ...

    Ihr hattet natürlich Recht: "Option Strict" war off

    Wenn ich dies jetzt mit meinen Worten interpretieren sollte, würde dies so aussehen:

    VB.NET-Quellcode

    1. Dim rdb1Control As Control = UserControl.FindControl("rdb1") 'Dim as Control, da von FindControl ein Element von Typ Control zurückgeliefert wird.
    2. Dim rdb as RadioButton = TryCast(rdb1Control, RadioButton )



    'Kurzschreibweise wäre dann wie gehabt:

    VB.NET-Quellcode

    1. Dim rdb1 As RadioButton = TryCast(UserControl.FindControl("rdb1"), RadioButton)


    Stimmt das so?

    Achja und vielen Dank wegen der sehr hilfreichen Info:Explizit und Implizit: Nachdem ich
    Option Strict On gestellt habe, sind gleich mehrere Fehler aufgetaucht.
    Auf jeden Fall werde ich jetzt immer auf "Option Strict On" einstellen um Fehler zu vermeiden.




    Zu den Options:

    Wenn ich ein neues VB-Dokument vor mir habe, Klasse, Interface, was auch immer, das erste was ich tue ist immer folgender Ausschnitt direkt oben in die erste Zeile hängen:

    VB.NET-Quellcode

    1. Option Explicit On
    2. Option Strict On
    3. Option Compare Binary
    4. Option Infer On


    BTT:

    Es stimmt so, ich würde dir aber den Zweizeiler empfehlen. Des weiteren beachte danach bitte diesen Satz:

    Kagurame schrieb:

    was impliziert, dass danach auf Nothing) geprüft weden muss

    Kagurame schrieb:

    was impliziert, dass danach auf Nothing) geprüft weden muss

    Wobei man das allerdings als "Fehler" von MS auslegen muss (IMHO)

    TryParse liefert einen Bool. Viele andere TryXXXX Funktionen liefern ebenfalls nen Bool. Andere (wie auch TryCast) liefern ein bestimmtes Objekt oder halt nothing. Das ganze ist sehr uneinheitlich und man hätte sich etwas mehr "Mühe" geben sollen. Mir PERSÖNLICH gefällt die Geschichte mit dem Bool eigentlich besser und ggf hätte man das halt so an allen Stellen machen sollen.
    Da stimme ich dir zu, Einheitlichkeit ist nicht gerade die Stärke von MS wenn man sich die ganzen Sachen da anguckt.
    Generell funktioniert es auch ohne die abschließende Prüfung, aber da wäre dann auch wieder der Sinn verfehlt... wenn dann an anderer Stelle die Fehler kommen (dann dummerweiße die allseits beliebten ObjectNullReferenceException´s). Liefe dann daraus hinaus, Performant den Fehler zu fressen... und an anderer Stelle noch verwirrter da zu sitzen ^^

    VBuchner schrieb:

    Warum brauch ich in diesem Fall überhaupt eine Typkonvertierung mit TryCast?

    VB.NET-Quellcode

    1. Dim rdb1 As RadioButton = TryCast(UserControl.FindControl("rdb1"), RadioButton)
    fragichmich auch.
    Jdfs. unter der Annahme, dass mit "rdb1" immer ein Radiobutton addressiert sein soll, brauchst du's nicht.
    Und wenn du das UserControl selbst geschrieben hast, und weißt, dass ein so benannter Radiobutton da ist, brauchst du ühaupt nix zu tryen, sondern kannst direkt casten:

    VB.NET-Quellcode

    1. Dim rdb1 As RadioButton = DirectCast(UserControl.FindControl("rdb1"), RadioButton)


    Und wenn du dir nicht sicher bist, ob "rdb1" existiert, dann brauchst du immer noch kein TryCast, sondern UserControl.FindControl("rdb1") gibt dir ja Nothing zurück, wenn "rdb1" nicht gefunden wurde.

    Erst wenn du garkein Plan hast, und möglicherweise eine Checkbox unter dem Namen "rdb1" da herumfährt - dann brauchst du TryCast, und das wird dann Nothing zurückgeben, wenn statt eines Radiobuttons eine Checkbox gefunden wurde - denn eine Checkbox kann man nicht in einen Radiobutton casten.