Auslesen von Klassen mit Nullwert (Nothing) - wie abfangen

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 19 Antworten in diesem Thema. Der letzte Beitrag () ist von dive26.

    Auslesen von Klassen mit Nullwert (Nothing) - wie abfangen

    Hallo Leute,

    ich deserialisiere JSON Strings mit Newtonsoft in eine Klasse.
    Nun lese ich die Klassen aus. Es kann auch vorkommen, dass ein Wert in der Klasse nichts enthält (nothing).

    Nun versuche ich per Code festzustellen ob der Wert "nothing" ist, aber es klappt nicht, bekomme dennoch die Fehlermeldung.
    Anbei mein Screenshot mit der Fehlermeldung dazu.

    VB.NET-Quellcode

    1. If Not IsNothing(Bestellung.deliveryInfo.firstName) Then ...


    VB.NET-Quellcode

    1. Public Class DeliveryInfo
    2. Public Property firstName As String
    3. ...



    EDIT: Gelöst

    Ich bin selbst draufgekommen.
    Nicht nur "firstName" gibt es nicht, sondern auch "deliveryInfo".
    Daher muss ich zuerst den übergeordneten node abfragen ;-).
    Ich lasse den Beitrag aber dennoch hier stehen, vielleicht hat jemand anders auch dieses Problem.

    VB.NET-Quellcode

    1. If Not IsNothing(Bestellung.deliveryInfo) Then
    2. If Not IsNothing(Bestellung.deliveryInfo.firstName) Then Mergeport_Orders(Index).Vorname = Bestellung.deliveryInfo.firstName.ToString
    3. If Not IsNothing(Bestellung.deliveryInfo.lastName) Then Mergeport_Orders(Index).Nachname = Bestellung.deliveryInfo.lastName.ToString
    4. If Not IsNothing(Bestellung.deliveryInfo.formatted) Then Mergeport_Orders(Index).Formatted = Bestellung.deliveryInfo.formatted.ToString
    5. End If

    Bilder
    • 07102022120609.jpg

      143,41 kB, 745×295, 51 mal angesehen
    Liebe Grüße
    Roland Berghöfer

    Meine aktuellen und kostenlos verwendbaren Tools (mit VB.NET erstellt): freeremarkabletools.com | priconman.com | SimpleCalendar | AudibleTouch | BOComponent.com | bonit.at

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „dive26“ ()

    Auch wenns schon gelöst ist, vielleicht ein Anreiz von mir.

    VB.NET-Quellcode

    1. Public NotInheritable Class Root
    2. Private Property FieldObjectOne As ObjectOne = Nothing
    3. Public Property ObjectOne As ObjectOne
    4. Get
    5. With Me
    6. If .FieldObjectOne Is Nothing Then FieldObjectOne = New ObjectOne
    7. Return .FieldObjectOne
    8. End With
    9. End Get
    10. Set(value As ObjectOne)
    11. With Me
    12. .FieldObjectOne = If(value Is Nothing, New ObjectOne, value)
    13. End With
    14. End Set
    15. End Property
    16. Sub New()
    17. End Sub
    18. End Class
    19. Public NotInheritable Class ObjectOne
    20. Private Property FieldText As String = String.Empty
    21. Public Property Text As String
    22. Get
    23. With Me
    24. If String.IsNullOrEmpty(.FieldText) Then .FieldText = String.Empty
    25. Return .FieldText
    26. End With
    27. End Get
    28. Set(value As String)
    29. With Me
    30. .FieldText = If(String.IsNullOrEmpty(value), String.Empty, value)
    31. End With
    32. End Set
    33. End Property
    34. Sub New()
    35. End Sub
    36. End Class


    So erstelle ich meine Klassen (auch zum Serialisieren von JSon oder Xml).
    Beim Get/Set der öffentlichen Member Root.ObjectOne und ObjectOne.Text wird intern überprüft, ob sie Nothing sind und wenn ja, wird Nothing durch etwas Sinnvolles ersetzt.
    Bläht den gesamten Code natürlich mehr auf, als wenn man einfach nur ​Public Property ObjectOne As ObjectOne oder ​Public Property Text As String als einfache Properties nimmt, aber es erschlägt so eigentlich alle NullReferenceExceptions.
    @BlueLagoonX

    Ja, so ginge es wohl auch. Aber bei ca. 120 Werten die so 120 Zeilen brauchen, wäre das unverhältnismäßig "aufgebläht", da hast Du Recht.
    Liebe Grüße
    Roland Berghöfer

    Meine aktuellen und kostenlos verwendbaren Tools (mit VB.NET erstellt): freeremarkabletools.com | priconman.com | SimpleCalendar | AudibleTouch | BOComponent.com | bonit.at
    Wenn man mit Objekten arbeitet, die Null sein könnten, empfiehlt es sich mit dem Stichwort "Nullable Types" auseinander zu setzen.
    Spart jedenfalls eine Menge If-Abfragerei.

    MSDN Doku
    @KingLM97

    ​Nullable Types kannte ich bisher noch nicht. War noch nicht auf meinem Schirm.

    Hört sich anfangs sehr verlockend an einfach ​Dim numberOfChildren? As Integer deklarieren zu müssen, aber wenn man dann doch wieder mit

    VB.NET-Quellcode

    1. ​If numberOfChildren.HasValue Then
    2. MsgBox("There are " & CStr(numberOfChildren) & " children.")
    3. Else
    4. MsgBox("It is not known how many children there are.")
    5. End If


    abfragen muss, ob sie null ist, dann ist das nicht viel anders als fragen ob sie ​nothing ist.

    Zudem geht das nicht mit Strings oder anderen Datentypen als Integer.

    Ich habe da jetzt keinen tieferen Sinn in den nullable types gefunden.
    Liebe Grüße
    Roland Berghöfer

    Meine aktuellen und kostenlos verwendbaren Tools (mit VB.NET erstellt): freeremarkabletools.com | priconman.com | SimpleCalendar | AudibleTouch | BOComponent.com | bonit.at
    @dive26

    Nullable-Types haben die Methode "GetValueOrDefault", damit erspart man sich theoretisch die ganzen If-Abfragen.

    dive26 schrieb:

    Zudem geht das nicht mit Strings oder anderen Datentypen als Integer.

    Gerade selbst getestet, du hast recht. War mir neu, ich benutze kein Visual Basic mehr, denn in C# geht das auf alle möglichen Datentypen. Und Dort ist auch seit .NET 5, meine ich zumindest, Nullable standardmäßig aktiviert.

    Wenn man das ordentlich durchzieht, kann einem das viel Arbeit und debuggen ersparen (mir jedenfalls :D ), mit Fehlermeldungen von wegen "NullReferenceException".
    @KingLM97

    Man könnte es so machen, was den Code etwas verkürzt:

    VB.NET-Quellcode

    1. ''' <summary>
    2. ''' Statt If Not IsNothing(art.parentId) Then Mergeport_Items(Index, Artikelindex).parentId = art.parentId.ToString
    3. ''' nur Mergeport_Items(Index, Artikelindex).parentId = GiveNotNullString(art.parentId)
    4. ''' </summary>
    5. ''' <param name="value"></param>
    6. ''' <returns></returns>
    7. Public Function GiveNotNullString(value As Object) As String
    8. If Not IsNothing(value) Then
    9. Return value.ToString
    10. Else
    11. Return ""
    12. End If
    13. End Function
    14. ''' <summary>
    15. ''' Statt If Not IsNothing(art.relativeQuantity) Then Mergeport_Items(Index, Artikelindex).Menge = CDbl(art.relativeQuantity)
    16. ''' nur Mergeport_Items(Index, Artikelindex).Menge = GiveNotNullDouble(art.relativeQuantity)
    17. ''' </summary>
    18. ''' <param name="value"></param>
    19. ''' <returns></returns>
    20. Public Function GiveNotNullDouble(value As Object) As Double
    21. If Not IsNothing(value) Then
    22. Return CDbl(value)
    23. Else
    24. Return 0
    25. End If
    26. End Function
    27. ''' <summary>
    28. ''' Statt If Not IsNothing(Bestellung.inHouseOrderingInfo.tableId) Then Mergeport_Orders(Index).tableId = CInt(Bestellung.inHouseOrderingInfo.tableId)
    29. ''' nur Mergeport_Orders(Index).tableId = GiveNotNullInteger(Bestellung.inHouseOrderingInfo.tableId)
    30. ''' </summary>
    31. ''' <param name="value"></param>
    32. ''' <returns></returns>
    33. Public Function GiveNotNullInteger(value As Object) As Integer
    34. If Not IsNothing(value) Then
    35. Return CInt(value)
    36. Else
    37. Return 0
    38. End If
    39. End Function
    40. ''' <summary>
    41. ''' Statt If Not IsNothing(pay.payOnDelivery) Then Mergeport_PaymentInfo(Index).payOnDelivery = CBool(pay.payOnDelivery)
    42. ''' nur Mergeport_PaymentInfo(Index).payOnDelivery = GiveNotNullBoolean(pay.payOnDelivery)
    43. ''' </summary>
    44. ''' <param name="value"></param>
    45. ''' <returns></returns>
    46. Public Function GiveNotNullBoolean(value As Object) As Boolean
    47. If Not IsNothing(value) Then
    48. Return CBool(value)
    49. Else
    50. Return False
    51. End If
    52. End Function
    Liebe Grüße
    Roland Berghöfer

    Meine aktuellen und kostenlos verwendbaren Tools (mit VB.NET erstellt): freeremarkabletools.com | priconman.com | SimpleCalendar | AudibleTouch | BOComponent.com | bonit.at
    In den letzten 3 Fällen kann man sich das sparen, da z.B. CInt(Nothing) eh 0 ergibt.
    Für die erste Funktion ginge es auch kürzer:

    VB.NET-Quellcode

    1. Public Function GetNotNullString(value As Object) As String
    2. Return If(value Is Nothing, String.Empty, value.ToString)
    3. End Function
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    @VaporiZed

    Meistens hast Du mit dem was Du schreibts Recht.
    Nur in diesem Fall denke ich, liegt die Sache etwas anders.

    n den letzten 3 Fällen kann man sich das sparen, da z.B. CInt(Nothing) eh 0 ergibt.


    Es werden keine Integer-, Double-, oder Boolean- oder Stringvariablen direkt auf Nothing geprüft, sondern JSON-Nodes.
    Das bedeutet z.B. bei Node pay.payOnDelivery könnte es sein, dass es "pay" gar nicht gibt.
    Liebe Grüße
    Roland Berghöfer

    Meine aktuellen und kostenlos verwendbaren Tools (mit VB.NET erstellt): freeremarkabletools.com | priconman.com | SimpleCalendar | AudibleTouch | BOComponent.com | bonit.at
    Und was wird dann beim Aufruf von Public Function GiveNotNullInteger(value As Object) As Integer als Parameterwert an die Methode übertragen? Ich wage zu behaupten: Nothing. Oder welchen Wert hat dann Value? Schließlich prüfst Du ja mit IsNothing auf Nothing. Wenn pay.payOnDelivery verwendet wird, wobei pay Nothing ist, schmiert das Programm schon vorher ab.
    Bilder
    • PreCrash.png

      25,58 kB, 541×283, 44 mal angesehen
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    @VaporiZed

    Passt eh was Du schreibst. Das ist genau das Problem. Wenn es vorher schon nicht existiert, dann kann ich es auch nicht der Funktion übergeben.

    Beispiel:Bestellung.inHouseOrderingInfo.tableId existiert nicht

    Dim IntegerWert As Integer = cint(Bestellung.inHouseOrderingInfo.tableId) = geht nicht, bringt Fehler.
    Dim IntegerWert As Integer = GiveNotNullInteger(Bestellung.inHouseOrderingInfo.tableId) = bringt auch einen Fehler

    If Not IsNothing(Bestellung.inHouseOrderingInfo.tableId) Then Mergeport_Orders(Index).Tischnummer= cint(Bestellung.inHouseOrderingInfo.tableId) = funktioniert.

    Also bringt es (für meinen Bedarf) nichts das in Funktionen zu verschachteln.
    Daher muss ich es leider mit dem If Not isNothing ... für jeden einzelnen Wert belassen.
    Liebe Grüße
    Roland Berghöfer

    Meine aktuellen und kostenlos verwendbaren Tools (mit VB.NET erstellt): freeremarkabletools.com | priconman.com | SimpleCalendar | AudibleTouch | BOComponent.com | bonit.at
    Hm, macht bei mir keinen Unterschied.
    Bilder
    • PreCrash.png

      29,14 kB, 800×290, 44 mal angesehen
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Ich werf' mal den ?-Operator: learn.microsoft.com/de-de/dotn…ull-conditional-operators in den Raum. Der gibt entweder den Wert oder Null zurück.

    Bestellung?.inHouseOrderingInfo?.tableId kann dann keine NullReference mehr schmeißen. Das erspart einem die ganze Tipparbeit.
    Nur der Vollständigkeit halber: Null-conditional Operators.

    VB.NET-Quellcode

    1. Dim tableId As Integer = If(​Bestellung?.inHouseOrderingInfo?.tableId, 0)

    dive26 schrieb:

    Public Function GiveNotNullString(value As Object) As String

    Warum dafür extra eine Funktion basteln? Die String-Klasse bietet doch String.IsNullOrWhitespace zum Überprüfen? Ich finde, da muss man nicht in drölfzig Funktion einspringen, die auch noch mit Boxing/Unboxing arbeiten. Deine Eigenschaften sind doch schon typisiert, du weißt doch, was du erwartest.
    @VaporiZed
    Hm, macht bei mir keinen Unterschied.

    Wahrscheinlich weil ich eine Klasse dahinter habe und Du nur eine Variable dimensioniert hast.

    @Gonger96
    Vielen Dank. Klingt Interessant. Probiere ich natürlich sofort aus ...

    VB.NET-Quellcode

    1. 'Alle drei Nodes im Beispiel sind nothing.
    2. Mergeport_Orders(Index).Vorname = Bestellung?.deliveryInfo?.firstName.ToString
    3. Mergeport_Orders(Index).tableId = CInt(Bestellung?.inHouseOrderingInfo?.tableId)
    4. Mergeport_Orders(Index).Abholdatum = CDate(Bestellung?.deliveryInfo?.deliveryTime) 'das funktioniert nicht


    Super, das mit den Strings und Integer funktioniert wunderbar.

    @ISliceUrPanties
    Dein Beispiel bringt in der IDE schon den Fehler ​Ein gemeinsamer Typ kann nicht abgeleitet werden, da mehrere Typen möglich sind..
    Liebe Grüße
    Roland Berghöfer

    Meine aktuellen und kostenlos verwendbaren Tools (mit VB.NET erstellt): freeremarkabletools.com | priconman.com | SimpleCalendar | AudibleTouch | BOComponent.com | bonit.at
    Meine Klasse ist Foo. Ja, man braucht eine Instanz. Ich habe beides. Aber das wird bei Dir nicht anders sein.

    dive26 schrieb:

    Ein gemeinsamer Typ kann nicht abgeleitet werden, da mehrere Typen möglich sind.
    Hm, G**gle kennt die Fehlermeldung nicht. Von welchem Datentyp ist denn tableId?
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    @VaporiZed
    Von welchem Datentyp ist denn tableId


    Im JSON ist es ein String. Ich brauche es aber als Integer. Daher wohl die Verwirrung ;-).

    Hm, G**gle kennt die Fehlermeldung nicht.

    Ich denke da ist das damit gemeint: learn.microsoft.com/de-de/dotnet/visual-basic/misc/bc33106
    Aber ich muss ehrlich gestehen, ich verstehe nicht was dort geschrieben steht ;-).
    Ich habe auch bisher noch nie eine If-Abfrage so mit Klammern in einer Zeile gemacht. Kenn nur das normale If then else elseif endif.
    Liebe Grüße
    Roland Berghöfer

    Meine aktuellen und kostenlos verwendbaren Tools (mit VB.NET erstellt): freeremarkabletools.com | priconman.com | SimpleCalendar | AudibleTouch | BOComponent.com | bonit.at
    Dim Foo = If(Bar = 0, 1, 2) ist eine Kurzform von

    VB.NET-Quellcode

    1. Dim Foo As Integer
    2. If Bar = 0 Then
    3. Foo = 1
    4. Else
    5. Foo = 2
    6. End If
    Also Ergebnis = If(Bedingung, ErgebniswertWennBedingungTrueErgibt, ErgebniswertWennBedingungFalseErgibt)

    ##########

    zur Vollständigkeit:

    VB.NET-Quellcode

    1. Dim Result = If(Foo?.Bar?.Baz?.Buzz, 3)
    2. '=
    3. Dim Result As Integer
    4. If Foo IsNot Nothing AndAlso Foo.Bar IsNot Nothing AndAlso Foo.Bar.Baz IsNot Nothing Then
    5. Result = Foo.Bar.Baz.Buzz
    6. Else
    7. Result = 3
    8. End If

    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „VaporiZed“ ()

    dive26 schrieb:

    Im JSON ist es ein String.

    Ist es im Json wirklich ein String, also so angegeben: "tableid": "123"? Finde ich missverständlich, da eine Id im Normalfall einen numerischen Typen impliziert. Oder steht die Zahl ohne Hochkomma da? Dann wäre die Definition in deiner Klasse falsch.

    dive26 schrieb:

    Dein Beispiel bringt in der IDE schon den Fehler

    Ja, weil ich davon ausging (weil du das Json nicht gezeigt hast), es handle sich um einen Integer :)
    @ISliceUrPantiesnull
    Ja, ist ein String. Das passt auch so, da die Table-ID laut API theoretisch auch Zeichen enthalten könnte. In meiner Anwendung wird Sie jedoch ausschließlich Nummern enthalten.

    Ich habe es jetzt für meine Bedürfnisse angepasst:

    VB.NET-Quellcode

    1. 'inHouse (InHouseOrderingInfo)
    2. If Not IsNothing(Bestellung.inHouseOrderingInfo) Then
    3. Mergeport_Orders(Index).WirdGeliefert = True
    4. Mergeport_Orders(Index).tableId = CInt(Bestellung?.inHouseOrderingInfo?.tableId)
    5. Mergeport_Orders(Index).tableDescription = Bestellung?.inHouseOrderingInfo?.tableDescription?.ToString
    6. Mergeport_Orders(Index).serviceAreaDescription = Bestellung?.inHouseOrderingInfo?.serviceAreaDescription?.ToString
    7. Mergeport_Orders(Index).serviceAreaId = Bestellung?.inHouseOrderingInfo?.serviceAreaId?.ToString
    8. End If
    Bilder
    • 10102022094441.jpg

      19,89 kB, 309×95, 36 mal angesehen
    Liebe Grüße
    Roland Berghöfer

    Meine aktuellen und kostenlos verwendbaren Tools (mit VB.NET erstellt): freeremarkabletools.com | priconman.com | SimpleCalendar | AudibleTouch | BOComponent.com | bonit.at