Software-Entwickler, die sich eine zeitlang mit der Office-Programmierung und somit mit VBA beschäftigt haben, werden die Methode nz kennen, die es ermöglicht sicher mit Null-Werten umzugehen. Die Methode prüft dabei den ersten Parameter Value auf NULL und ersetzt diesen, wenn ja, mit dem Wert des zweiten Parameters ValueIfNull. Ist unklar, ob eine bestimmte Variable während der Laufzeit den Wert NULL enthalten kann, sollte man sie vorsichtshalber über die nz-Methode laufen lassen. Dies funktioniert mit beliebigen Datentypen, denn die Parameter der Methode sind vom Typ Variant.
Benötigt wird nz vor allem im Umgang mit Daten aus Datenquellen wie SQL-Server, Access oder ähnlichem, um beim Zugriff auf ein Datenfeld Null-Exceptions zu verhindern. In allen VB-Sprachen haben die einzelnen Datentypen meist einen Standardwert, Datenfelder aber oft nicht.
Die Spezialität ist allerdings auf VBA beschränkt. So gibt es sie weder in der Schwestersprache Visual Basic 6.0 noch in VB.NET. In Letzterer hat man zwar einige andere Prüfmethoden wie String.IsNullOrEmpty oder ähnliches, aber eine Ersetzungsmethode wie nz sucht man vergebens. Sie nachzubauen ist natürlich nicht besonders schwer, auch wenn man hier auf die in .NET unterschiedlichen NULL-Werte achten muss:
Public Class Tools
Public Shared Function nz( _
ByVal strValue As String, _
ByVal strReplacement As String) As String
Try
If strValue Is Nothing OrElse IsDBNull(strValue) Then
Return strReplacement
Else
Return strValue
End If
Catch e As Exception
Return strReplacement
End Try
End Function
End Class
Das Beispiel ist nun ein nz-Ersatz für String-Variablen. Um die universelle Einsetzbarkeit bezüglich des Variant-Datentyps umzusetzen, könnte man nun für jeden Datentyp eine überladene Methode schreiben oder die Datentypen der Parameter als Object definieren. Letzteres würde allerdings bedeuten auf Typsicherheit zu verzichten, was in .NET selten eine gute Idee ist.
Es werde generisch...
Ein wesentlich besserer Ansatz ist der Einsatz von Generics:
Public Class Tools
Public Overloads Shared Function nz(Of T)( _
ByVal Value As T, _
ByVal Replacement As T) As T
Try
If Value Is Nothing OrElse IsDBNull(Value) Then
Return Replacement
Else
Return Value
End If
Catch e As Exception
Return Replacement
End Try
End Function
End Class
Vorteil ist, dass einmal der Datentyp bestimmt wird und im folgenden die Parameter und der Rückgabewert automatisch vom gleichen Typ sind bzw. sein müssen. Im Einsatz würde der Aufruf dann folgendermaßen aussehen:
strMeineVariable = Tools.nz(Of String) _
(MeinDataSet.Tables(0).Row(0).Item("MeinDatenfeld").ToString, "")
Schon ganz nett, aber für meinen Geschmack noch etwas zuviel Schreibarbeit, zumal ich die Methode in meinem Beispiel auch noch in der Klasse Tools untergebracht habe, statt in einem Modul.
Als Erweiterung zu kürzerem Code
Mit der Einführung des .NET-Frameworks 3.5, d.h. C# 3.0 und Visual Basic 2008, haben die sog. Extensions Einzug gehalten, also Erweiterungsmethoden, die bestimmte Klassen erweitern können, ohne von ihnen ableiten zu müssen. Dies gilt insbesondere für Datentypen wie String, die nicht beerbbar sind.
Es sind virtuelle, statische Methoden, die die Basismethoden der Klasse um eigene Funktionalität ergänzen. In VB.NET müssen Erweiterungsmethoden in einem Modul deklariert sein und können nur vom Typ Sub oder Function sein. Der Datentyp des ersten Parameters der Methode definiert den zu erweiternden Typen.
Für unsere generische nz-Methode nahezu ideal:
Imports Microsoft.VisualBasic
Imports System.Runtime.CompilerServices
Public Module Extensions
<Extension()> _
Public Function nz(Of T)(ByVal Value As T, ByVal Replacement As T) As T
Try
If Value Is Nothing OrElse IsDBNull(Value) Then
Return Replacement
Else
Return Value
End If
Catch e As Exception
Return Replacement
End Try
End Function
End Module
Der Einsatz der Methode ist nun vollkommen unproblematisch und intuitiv:
... = MeinDataSet.Tables(0).Row(0).Item("MeinDatenfeld").ToString.nz("")
In puncto Intellisense klinken sich Erweiterungsmethoden in die Liste der verfügbaren Methoden eines Objekts (in unserem Fall in alle) mit einem etwas anderen Icon ein, an dem sie direkt zu erkennen sind.
Lesenswert in diesem Zusammenhang:
Anstoss für diesen Artikel ist eine neue Reihe von Patrick A. Lorenz in der dotnetpro: Patricks .NET Extensions