TryCast vereinfacht Typkonvertierungen

Veröffentlicht: 31. Okt 2005

Von Mathias Schiffer

Wenn Variableninhalte einander zugewiesen werden sollen, sind oft unterschiedliche Typen im Spiel. Für formvollendete Programmierung ist die explizite Typumwandlung (Casting) nicht nur Kür, sondern Pflicht.

Visual Basic-Programmierer haben vor Visual Basic .NET von einer Funktionalität profitiert, die sich als "implizite Typkonvertierung" beschreiben lässt: Sollten Variablen unterschiedlicher Typen ihre Werte austauschen, so sorgte VB völlig eigenständig für eine potenziell passende Typkonvertierung. Eine explizite Konvertierung war möglich, aber nicht zwingend notwendig. Mit Visual Basic .NET steht diese Freiheit noch immer zur Verfügung - endlich aber auch eine Möglichkeit, zumindest potenziell kritische Typkonvertierungen nicht implizit zu erlauben.

Dank "Option Strict On" (das leider nicht Installations-Standardeinstellung von Visual Studio .NET ist) sind Sie zumindest in solchen Fällen zur expliziten Typkonvertierung mittels CType oder DirectCast gezwungen, in denen ein "breiterer Datentyp" in einen "schmaleren Datentyp" überführt werden soll. Hiermit entspricht das Verhalten dem von C#. So können Sie etwa trotz "Option Strict On" noch immer implizit einen Integer- in einen Long-Wert überführen oder eine Referenz auf ein bestimmtes Objekt einer Object-Variablen zuweisen, da ein Verlust oder eine inhaltsändernde Bedeutungsänderung nicht möglich ist. Der Rückweg vom Long in den Integer oder von Object zu einem bestimmteren Objekttyp hingegen erfordert bei C# wie bei "Option Strict On" auch unter VB.NET, dass Sie diese Typkonvertierung - unabhängig vom konkreten Wert - explizit im Sourcecode formulieren.

Wo explizite Typkonvertierungen notwendig werden, besteht also definitorisch immer das Risiko, dass der Datentyp der aufnehmenden Variablen denjenigen der abgebenden Variablen nicht darstellen kann. Das einfachste Beispiel ist ein großer numerischer Wert in einer Long-Variablen, der bei der Übergabe an eine Integer-Variable für einen Überlauf sorgt, weil die Integer-Variable einen so großen Wert gar nicht aufnehmen kann. Die Folge einer solchen Konvertierung ist die Auslösung einer Exception (hier konkret einer OverflowException), also eines Fehlers.

Das wiederum bedeutet, dass alle notwendigen expliziten Typkonvertierungen eigentlich durch eine Fehlerbehandlung abgesichert werden müssten, um auch auf unerwartete Ursprungswerte ohne Probleme reagieren zu können. Alternativ könnte für jede Typkonvertierung eine vorgelagerte Werteprüfung der abgebenden Variablen implementiert werden.

C# bietet für dieses Problem den "As"-Operator (der nichts mit dem "As"-Schlüsselwort von Visual Basic .NET zu tun hat!): Er sorgt dafür, dass entweder eine erfolgreiche Typkonvertierung erfolgt oder aber die Zielvariable den Initialisierungs-Pseudowert Null erhält (deswegen funktioniert diese Hilfe leider nur für Referenztypen: Wertetypen haben keine "neutralen Elemente"). Somit ist für die explizite Typkonvertierung eines Referenztyps nicht nur keine Ausnahmebehandlung notwendig, sondern es kann sogar eine Fehler vermeidende Vorabprüfung des umzuwandelnden Typs entfallen.

Bis zur Version Visual Studio 2005 blieb dieser Weg Visual Basic .NET-Programmierern vorenthalten. Neu in Visual Basic .NET ist seit Version 2005 das Schlüsselwort "TryCast", das dem C#-Verhalten von "As" entspricht: TryCast führt ebenfalls nur für Referenztypen eine explizite Typkonvertierung durch, die bei einem Problem keine Ausnahme auslöst, sondern den annehmenden Wert mit dem Pseudowert Nothing (dem VB-Äquivalent von Null) versorgt.

Der Erfolg der durch TryCast vorgenommenen Typkonvertierung lässt sich bei Bedarf einfach durch eine Is-Abfrage der annehmenden Variable auf Nothing überprüfen, eine vorherige explizite, zusätzliche Typüberprüfung entfällt (mit entsprechenden Laufzeitvorteilen):

' Beispielvorgehen in Visual Basic .NET *ohne* TryCast
  Private Function ReturnTypeCode(ByVal obj As Object) As String
  
    If TypeOf obj Is IConvertible Then  ' Explizite Typprüfung
  
      Dim objConverted As IConvertible = DirectCast(obj, IConvertible) ' Hier implizite, zusätzliche Typprüfung (redundant)
      ' Beschreibenden Rückgabewert erzeugen
      Return "Typcode: " & objConverted.GetTypeCode().ToString
  
    Else
  
      ' Typ des übergebenen Objekts passt nicht
      Return obj.ToString & " implementiert IConvertible nicht."
  
    End If
  
  End Function
  
  
  ' Beispielvorgehen in Visual Basic .NET *mit* TryCast (erst ab Version 2005):
  Private Function ReturnTypeCode(ByVal obj As Object) As String
  
    ' TryCast ist entweder erfolgreich oder returniert Nothing:
    Dim objConverted As IConvertible = TryCast(obj, IConvertible)
  
    If objConverted Is Nothing Then
  
      ' Typ des übergebenen Objekts passt nicht
      Return obj.ToString & " implementiert IConvertible nicht."
  
    Else
  
      ' Beschreibenden Rückgabewert erzeugen
      Return "Typcode: " & objConverted.GetTypeCode().ToString
  
    End If
  
  End Function

Für Wertetypen müssen jedoch auch weiterhin entweder eine Ausnahmebehandlung für explizite Typumwandlungen vornehmen oder aber vor einer Typkonvertierung den Wert der abgebenden Variablen selber darauf prüfen, ob er den Wertebereich der annehmenden Variablen überschreitet: Dank der Möglichkeit der Überladung von Funktionen wäre etwa eine universelle, vorab einzusetzende Hilfsfunktion "CanCast" denkbar.

Der Nutzen einer solchen Vorabprüfung ist jedoch nicht generell einschätzbar, insbesondere mit Blick auf die Aufrufhäufigkeit und entsprechende Laufzeitfolgen, sondern ist von Fall zu Fall unterschiedlich zu bewerten. Oft genug ist die weniger begeisternde Ausnahmebehandlung die bessere Wahl.

Mathias Schiffer widmet sich als freier Technologievermittler und Entwickler großen Projekten ebenso wie arbeiterleichternden Alltagslösungen. Seit Jahren gibt er sein Wissen und seine Erfahrungen in unzähligen Publikationen und Beratungen auch an andere Entwickler und Entscheider weiter. Sie erreichen Mathias Schiffer per E-Mail an die Adresse Schiffer@mvps.org.