Rubrik: .NET | VB-Versionen: VB2008 | 15.05.09 |
![]() Im Framework-VB stellt 'Nothing' offenbar einfach einen Speicherbereich dar, in dem alle Bits auf '0' gesetzt sind. Angemessen wäre deshalb die Bezeichnung 'Null', die in der VB-Dokumentation auch gelegentlich benutzt wird (z.B. in Zusammenhang mit der Nullable-Struktur). | ||
Autor: Manfred Bohn | Bewertung: ![]() ![]() ![]() ![]() ![]() | Views: 21.203 |
Wohl aus Gründen der Kompatibilität mit früheren VB-Versionen (vgl. unten) ist aber die Bezeichnung 'Nothing' weiterverwendet worden. 'Nothing' enthält Methoden wie 'GetType' oder 'ToString'. Die können aber nicht benutzt werden, weil 'Nothing' in dem Fall als eine nicht vorhandene Referenz behandelt wird. Es kommt deshalb zur 'NullReferenceException'.
1. Nothing' wird - abhängig vom Datentyp der Variable - unterschiedlich verwendet und verarbeitet:
Bei Referenztyp-Variablen dient die Zuweisung von 'Nothing' dem Lösen eines evt. vorhandenen Objektverweises. Beim Vergleich mit dieser Speicherstelle wird geprüft, ob ein Verweis auf ein vorhandenes Objekt besteht.
Bei Variablen eines numerischen Werttyps wird bei Zuweisungen aus diesem Speicherbereich die '0' gelesen und entsprechend konvertiert (z.B. 0&, 0D, 0.0#). Diese Umwandlungen (Anpassung der Anzahl der Null-Bits auf die Länge der Variable) scheinen als Erweiterungskonvertierungen eingerichtet zu sein. Bei Vergleichs-Operationen mit Variablen des Werttyps wird jeweils auf den enthaltenen '0'-Wert geprüft.
Als Werttyp (Null-Wert) wird 'Nothing' wie ein Integer (System.Int32) behandelt (z.B. bei inferentieller Deklaration). Trotzdem kann 'Nothing' auch bei 'Option Explicit On' auf Variable des Typs 'Byte' oder 'Short' direkt zugewiesen werden (keine einschränkende Konvertierung).
Bei der Zuweisung auf eine Variable des Datentyps 'Date' entspricht 'Nothing' dem Initialisierungs-Datum: "01.01.0001 00:00:00". (In der VB-Dokumentation werden Initialisierungswerte als 'Standardwerte' bezeichnet.)
Bei Variablen des Typs 'Char' entspricht 'Nothing' dem ASCII-Code '0', wie er von der Funktion 'Chr' (in Microsoft.Visualbasic.Conversion) beim Parameter '0' geliefert wird. Die Konstante 'vbNullChar' entspricht einer STRING-variable, die dieses Zeichen enthält. Sie ist nicht gleich dem Null-Zeichen.
Dim c1, c2 As Char c1 = Nothing c2 = Microsoft.VisualBasic.Chr(0) If c1.Equals(c2) Then Stop ' wird ausgelöst If c1.Equals(Microsoft.VisualBasic.vbNullChar) Then Stop ' wird nicht ausgelöst If c1 = Microsoft.VisualBasic.vbNullChar Then Stop ' wird ausgelöst
Bei Zeichenfolgen-Variablen ('String'/Referenztyp mit speziellem Verhalten) kann 'Nothing' die Null-Referenz der String-Variable herbeiführen, es kann aber keine Zeichen in einem String überschreiben und den String auch nicht verkürzen.
Dim str1 As String = Nothing ' Null-Referenz If str1 = Microsoft.VisualBasic.vbNullChar Then Stop ' wird nicht ausgelöst If str1 = Microsoft.VisualBasic.vbNullString Then Stop ' wird ausgelöst str1 = "XXX" Mid(str1, 2) = Nothing ' Mid-Statement für Zeichenersetzung if str1 <> "XXX" then stop ' wird nicht ausgelöst str1 = cstr(Nothing) ' Null-Referenz
Obwohl 'Nothing' dem Null-Zeichen (ASCII) entspricht, verhält es sich nach der expliziten Umwandlung in einen String nicht wie ein Null-Zeichen, sondern wie ein zeichenloser String.
' wird ausgelöst If Microsoft.VisualBasic.Chr(0).Equals(Nothing) Then Stop ' wird nicht ausgelöst If CStr(Microsoft.VisualBasic.Chr(0)).Equals(CStr(Nothing)) Then Stop
Übergibt man 'Nothing' als Parameter an eine Funktion, die einen Werttyp erwartet, erhält die Funktion tatsächlich den Wert 0. Bei einem Referenztyp ist es die Null-Referenz. Die vorgegebenen Standardwerte optionaler Parameter werden durch die explizite Übergabe von 'Nothing' ggf. überschrieben. Es kann also einen Unterschied ausmachen, ob man einem optionalen Parameter nichts oder 'Nothing' übergibt.
2. Microsoft.Visualbasic
Die Funktionen in 'Microsoft.Visualbasic' betrachten 'Nothing' eingeschränkter als die Framework-Methoden, nämlich nur als Null-Referenz, aber nicht als Null-Wert.
Die in 'Microsoft.VisualBasic.Information' enthaltene Funktion 'IsNothing' gibt 'true' zurück, wenn eine Variable des Referenztyps keinen Objektverweis enthält - in allen anderen Fällen 'false', d.h. eine Variable des Werttyps, die '0' enthält wird NICHT als 'Nothing' identifiziert.
Dim i As Integer = Nothing ' i = 0% ' wird nicht ausgelöst If Microsoft.VisualBasic.Information.IsNothing(i) Then Stop ' wird ausgelöst If i = Nothing Then Stop ' wird von der IDE nicht zugelassen (wg. Werttyp) If i Is Nothing Then Stop
'Nothing' wird von der Funktion 'IsNothing' nicht als 'Null', sondern als Null-Referenz interpretiert. Dies gilt auch für die Funktion 'IsReference'. 'IsNumeric' identifiziert 'Nothing' ebenfalls nicht als einen numerischen Wert.
' wird ausgelöst If Microsoft.VisualBasic.Information.IsReference(Nothing) Then Stop ' wird NICHT ausgelöst If Microsoft.VisualBasic.Information.IsDBNull(Nothing) Then Stop ' wird NICHT ausgelöst If Microsoft.VisualBasic.Information.IsNumeric(Nothing) Then Stop
Die 'IsNothing'-Methode benötigt bei der Prüfung von Referenz-Variablen meist mehr Rechenzeit als der direkte 'Is Nothing'-Vergleich.
Auch bei Stringvariablen ist zu unterscheiden zwischen Framework-Methoden (Nothing = Null-Referenz) und den Methoden, die in 'Microsoft.Visualbasic' enthalten sind (Nothing = Leerstring). Diese Regel gilt aber nicht für die Funktion 'IsNothing'.
Dim str as string = Nothing ' wird ausgelöst If Microsoft.Visualbasic.Information.IsNothing(str) Then Stop ' l = 0, als wäre es ein Leerstring Dim l As Integer = Microsoft.VisualBasic.Len(str) ' l = 0, Nothing -> Nullzeichen l = Microsoft.VisualBasic.Strings.Asc(Nothing) ' Ausnahme, als wäre 'str' ein Leerstring l = Microsoft.VisualBasic.Strings.Asc(str) ' gibt einen Leerstring zurück Microsoft.VisualBasic.Strings.Trim(Nothing)
Bei String-Operationen muss man vorsichtig sein, weil einige Framework-Methoden (System.String) und Basic-Methoden zwar gleich benannt sind, sich bei 'Nothing' aber unterschiedlich verhalten (z.B. 'Trim', 'Split'). Im Kapitel 'Zeichenfolgenbearbeitung: Zusammenfassung' der VB-Dokumentation sind die Basic-Methoden gelistet.
3. String-Verkettung
Bei String-Verkettungs-Operationen gibt es einen interessanten Effekt:
Der &-Operator erweitert die Operanden zunächst zu Strings, bei 'Nothing' zu Leerstrings. Für den +Operator gilt das nicht. Die IDE identifiziert 'Nothing' in dem Fall nämlich als Null-Wert.
Anders ist es, wenn man 'Nothing' zuerst (per 'CChar') in ein NUL-Zeichen umwandelt. Die Methode 'String.ConCat' akzeptiert auch Object-Parameter und wandelt Null-Referenzen in Leerstrings um.
Dim str3 As String = Nothing ' nicht referenzierte Stringvariable str3 = Nothing & Nothing & Nothing ' es entsteht ein Leerstring If str3 = String.Empty Then Stop ' wird ausgelöst str3 = cstr(Nothing) & cstr(Nothing) ' es entsteht ein Leerstring If str3 = String.Empty Then Stop ' wird ausgelöst str3 = CChar(Nothing) & CChar(Nothing) ' String der Länge 2 / NUL-Zeichen str3 = CChar(Nothing) + CChar(Nothing) ' String der Länge 2 str3 = Nothing str3 = String.concat(str3, str3, str3) ' es entsteht ein Leerstring if str3 = String.Empty then stop ' wird ausgelöst
4. Wert-Typ
In Zusammenhang mit Variablen eines Werttyps eingesetzt, verhält 'Nothing' sich wie eine Variable des Wertes '0', die den üblichen (Erweiterungs-) Konvertierungen folgt. Einige Beispiele:
Dim shrt As Short = Nothing \ 2 ' shrt = 0 Dim dbl As Double = Math.Sqrt(Nothing) ' dbl = 0 dbl = 2 / Nothing ' dbl = PositiveInfinity dbl = Nothing ^ Nothing ' dbl = 1 Dim dec As Decimal = 1D / Nothing ' IDE erkennt Division durch '0' Math.Sign(Nothing) ' = 0 Dim dd As Double = 100.0# / (1.0# / Nothing) ' = 0.0# echter VB-Grusel Const x As Double = Nothing ' Konstante mit dem Wert 0 If x <> Nothing Then Stop ' wird nicht ausgelöst
5. DBNull
Die Singleton-Klasse 'DBNull' wird verwendet, um bei Datenbankabfragen anzuzeigen, dass kein Wert in einer Tabellen-Zelle enthalten ist (=fehlender Wert). Da es sich dabei um eine (nur einmal vorhandene) Objekt-Instanz handelt, ist dieser Wert nie 'Nothing'. Abgefragt, verglichen oder zugewiesen wird er durch die 'ReadOnly'-Eigenschaft 'DBNull.Value'. Auf 'DBNull' kann nichts zugewiesen werden, weil es sich dabei um einen Typ handelt.
In System.Data.DataRow steht die Methode 'IsNull' zur Verfügung, durch die fehlende Werte identifiziert werden können.
Dim dtb As New Data.DataTable Dim value(0) As Object Dim Colnam As String = "Spalte" With dtb .Columns.Add(Colnam, GetType(String)) .Columns(0).AllowDBNull = True ' Nullwerte zulassen ' .Columns(0).DefaultValue = "anything" ' Standardwert definieren value(0) = System.DBNull.Value .Rows.Add(value) If .Rows(0).IsNull(Colnam) Then Stop ' wird ausgelöst If .Rows(0).Item(Colnam) Is Nothing Then Stop ' wird nicht ausgelöst If .Rows(0).Item(0).GetType.Equals(GetType(System.DBNull)) Then Stop value(0) = Nothing .Rows.Add(value) If .Rows(1).IsNull(Colnam) Then Stop ' hängt von DefaultValue ab If .Rows(1).Item(Colnam) Is Nothing Then Stop ' wird nicht ausgelöst If .Rows(1).Item(Colnam).GetType.Equals(GetType(System.DBNull)) Then Stop End With
Gleichgültig, ob man 'Nothing' oder 'DbNull.value' auf eine Zelle der Datatable (System.Data) zuweist, die Zelle enthält den Typ 'DBNull' - und zwar unabhängig davon, ob der Typ der Spalte als ein Wert- oder als ein Referenztyp eingerichtet worden ist. Ist jedoch ein Standardwert für die Spalte definiert worden, wird bei der Zuweisung von 'Nothing' der Standardwert in die Zelle eingetragen.
6. Was noch?
Auch bei Pointer-Variablen (z.B. 'System.IntPtr') wird 'Nothing' als '0' verarbeitet.
Dim ptr As System.IntPtr = Nothing If IntPtr.Zero.Equals(ptr) Then Stop ' wird ausgelöst
Die VB-Dokumentation schlägt vor, für die Prüfung, ob einer Pointer-Variable ein Wert ungleich '0' zugewiesen worden ist, statt 'Nothing' 'Zero' zu verwenden! 'Nothing' entspricht nämlich angeblich nicht 'Zero'.
Zuweisungen von Werten oder Referenzen auf 'Nothing' gelten als 'syntaktischer Fehler'.
Der 'CType'-Operator akzeptiert 'Nothing' und gibt 'Nothing' zurück. Die IDE überwacht die Konvertierbarkeit der Datentypen.
Dim x As Drawing.Bitmap = CType(Nothing, Drawing.Bitmap)
Interessant ist auch das Verhalten von Variablen des Typs 'Object', die so flexibel sind, dass sie Null-Referenzen, Referenzen oder Werte beliebiger Art enthalten können. Dabei passen sie sich dem jeweils zugewiesenen Typ an.
Dim obj As Object If obj Is Nothing Then Stop ' wird ausgelöst obj = 120 ' Integer-Objekt (Werttyp) If obj Is Nothing Then Stop ' wird nicht ausgelöst obj = Nothing ' Null-Referenz If obj Is Nothing Then Stop ' wird ausgelöst obj = New Object ' eine Object-Variable entsteht If obj Is Nothing Then Stop ' wird nicht ausgelöst If Microsoft.VisualBasic.IsNothing(obj) Then Stop obj = System.DBNull.Value If obj Is Nothing Then Stop ' wird nicht ausgelöst
'Structures' sind Werttypen, auch wenn sie Elemente enthalten, die Referenztypen sind. Weist man einer Structure-Variable den Wert 'Nothing' zu, werden alle Member initialisiert - Werttypen = 0, Referenztypen = Null-Referenz.
Public Structure Test Dim a As Integer Dim b As String Dim c As Text.StringBuilder End Structure Dim stc As Test stc.a = 100 stc.b = "soso" stc.c = New Text.StringBuilder("jaja") stc = Nothing ' --> a = 0; b,c = Nothing
Selbsterstellte Enumerationen sollten immer einen 0-Wert ('None') enthalten, weil Enumerations-Variable grundsätzlich mit 'Nothing' initialisiert werden. (Näheres dazu: VB-Dokumentation, Abschnitt 'FlagsAttribute-Klasse', Richtlinien).
Eine Array-Variable, die keine Referenz besitzt, wird von 'IsArray' nicht als Array identifiziert. Eine Array-Variable, die nur Null-Referenzen enthält, aber schon:
Dim arr As System.Array = Nothing ' wird nicht ausgelöst If Microsoft.VisualBasic.Information.IsArray(arr) Then Stop Dim iarr() As Integer ' wird nicht ausgelöst If Microsoft.VisualBasic.Information.IsArray(iarr) Then Stop Dim sarr(100) As String 'Array mit Null-Referenz-Elementen ' wird ausgelöst If Microsoft.VisualBasic.Information.IsArray(sarr) Then Stop
7. Was fehlt?
Einiges, z.B. Nullables: Werttypen, die auch 'Nothing' (= kein Wert vorhanden) enthalten können.
In VB ist es möglich Werttypen in einer Nullable-Struktur zu 'kapseln", die zusätzlich notiert, ob ein gültiger Wert oder 'Nothing' zugewiesen worden ist (Eigenschaft: 'HasValue'). Bei diesen Variablen ist kein Standardwert definiert. Die Initialisierung dieser Variablen entspricht zwar 'Nothing', aber die Eigenschaft 'HasValue`= false gesetzt.
Obwohl Sie einer Variablen eines auf NULL festlegbaren Typs 'Nothing' zuweisen können, ist es nicht möglich, diese mittels Gleichheitszeichen auf Nothing zu überprüfen. Der Vergleich mithilfe des Gleichheitszeichens, someVar = Nothing, ergibt immer 'Nothing' (Es handelt sich also nicht um einen boolschen Vergleich, sondern TriState!). Sie können die 'HasValue'-Eigenschaft der Variablen auf 'False' überprüfen oder eine Überprüfung mithilfe des Operators 'Is' oder 'IsNot' vornehmen (VB-Doku).
Collections.BitArray: Bei Zuweisung von 'Nothing' werden nicht die Bits 'false', sondern die Variable erhält die Null-Referenz.
Listen, Steuerelemente, ADO/SQL ....
Hinweis für VB6-Umsteiger:
Wenn Sie sich jetzt wundern, liegen Sie richtig.
In VB6 ist 'Nothing' als ein 'nicht vorhandenes Objekt' implementiert.
'Nothing' dient ausschließlich zur Überprüfung, ob von Referenz-Variablen auf eine Objektinstanz verwiesen wird bzw. zum Löschen des Objekt-Verweises.
In VB6 kann man 'Nothing' nicht auf Werttypen zuweisen. Da 'Nothing' ein Objekt ist, wäre dafür die Verwendung der 'Set'-Anweisung erforderlich und die ist bei Werttypen nicht erlaubt.
Auch der Vergleich einer Variable vom Werttyp mit 'Nothing' ist in VB6 unzulässig. Der Versuch führt zur Meldung "ungültige Verwendung eines Objekts".
Dieses Verhalten ist sinnvoll, weil Werttypen niemals 'Nothing' sein können, da sie immer einen Wert (ggf. den Initialisierungswert) enthalten. Die Gleichsetzung von '0' und 'Nothing' gibt es in VB6 nicht.