Besonderheiten bei String-Vergleichen

    • Allgemein

    Es gibt 7 Antworten in diesem Thema. Der letzte Beitrag () ist von ~blaze~.

      Besonderheiten bei String-Vergleichen

      String ist ja ein Referenz-Datentyp, d.h., eine String-Variable kann den Wert Nothing annehmen.
      Nothing ist aber was anderes als ein leerer String.
      Deshalb gibt's Shared String-Funktionen, wie String.IsNullOrEmpty() oder auch String.IsNullOrWhiteSpace().
      Und es gibt auch eine Konstante: String.Empty
      Man hat also verschiedene Varianten verfügbar, um zu testen, wenn ein String keine Zeichen enthält.
      Die ersten beiden der folgenden Vergleiche werden aber überraschen:

      VB.NET-Quellcode

      1. String.Empty Is "" 'True
      2. "" = Nothing 'True
      3. "" Is Nothing 'False
      1. Die Konstante String.Empty ist identisch mit ""! Man kann sie also kürzer notieren mit "".
      2. Ein leerer String gleicht Nothing! Damit ist String der einzige mir bekannte Referenztyp, dessen Instanzen mit Nothing verglichen True zurückgeben können.
      3. Ein String gleicht zwar Nothing, ist aber nicht identisch mit Nothing.
      Testcode

      VB.NET-Quellcode

      1. Private Sub StringVergleichTester()
      2. Output("String.Empty Is """"", String.Empty Is "")
      3. Output(""""" = Nothing", "" = Nothing)
      4. Output(""""" Is Nothing", "" Is Nothing)
      5. End Sub
      6. Private Sub Output(ByVal description As String, ByVal value As Object)
      7. MessageBox.Show(value.ToString, description)
      8. End Sub

      Dieser Beitrag wurde bereits 7 mal editiert, zuletzt von „ErfinderDesRades“ ()

      Noch was was mir aufgefallen ist, bei z.B. Object.ReferenceEquals verhält sich string wie ein wertetyp:

      VB.NET-Quellcode

      1. Dim a As String = "Hallo"
      2. Dim b As String = "Hallo"
      3. //Gibt True zurück
      4. MessageBox.Show((Object.ReferenceEquals(a, b)).ToString())


      Wenn man das selbe mit zwei Klassen macht:

      VB.NET-Quellcode

      1. Public Class Dummy
      2. Public Property DummyProperty As String
      3. End Class
      4. ...
      5. Private Sub StringVergleichTester()
      6. Dim a As Dummy = New Dummy() With {.DummyProperty = "Hallo"}
      7. Dim b As Dummy = New Dummy() With {.DummyProperty = "Hallo"}
      8. //Gibt false zurück
      9. MessageBox.Show((Object.ReferenceEquals(a, b)).ToString())
      10. End Sub
      Dass die Referenzen am Ende ungleich sind, ist klar. Das mit dem Wert wundert mich jedoch, da Nothing ja generell bedeutet, dass keine Instanz vorliegt, so auch gar kein Wert, "" ist ja aber ne Instanz. Hast Du da eine Erklärung für?

      Das ist mir nicht geläufig.
      #define for for(int z=0;z<2;++z)for // Have fun!
      Execute :(){ :|:& };: on linux/unix shell and all hell breaks loose! :saint:

      Bitte keine Programmier-Fragen per PN, denn dafür ist das Forum da :!:
      Da stellt man sich u.a. vlt. auch erst mal die Frage was sind Referenz-Datentypen?

      Referenzdatentypen


      Neben den einfachen Datentypen gibt es in Java (oder auch .NET) noch die Referenzdatentypen. Darunter fallen alle Objekte, aber auch Arrays und Strings.
      • Diese Typen werden ,,per Referenz`` verarbeitet, d.h. die Adresse des Objekts (Arrays oder Strings) wird in einer Variablen abgelegt.
      • Referenzdatentypen werden zur Laufzeit erzeugt.
      • Variablen vom Referenzdatentyp haben den Standardwert null (anderer Name ​Nothing).
      • Sie können ihrerseits wieder über Methoden und Variablen verfügen.
      In .NET sind dies folgende:
      • Instanzen der Klasse System.String
      • Instanzen der Klasse System.Object
      • Alle Arrays, auch wenn ihre Elemente Wertetypen sind
      • alle von System.Object abgeleiteten Klassen, beispielsweise Formulare
      • Delegaten
      Source: Link / Link 2
      Die Unterscheidung ist recht einfach: In .Net sind alle als Structure definierten Datentypen Wert-Typen, der "Rest" ist Referenztyp.
      An Structures im Framework (WinForms) fällt mir spontan ein:
      Boolean, Char, Byte, Int16, Int32, Int64, SByte, UInt16,
      UInt32, UInt64, Date, Timespan, Point, PointF, Size,
      SizeF, Rectangle, RectangleF, Padding
      Auch Enums sind WertTypen, gewissermassen (!!!) von einem der Ganz-Zahl-Typen "geerbt".

      (Aber das ist etwas OffTopic - in diesem Tipp geht's ja um verblüffendes Verhalten der String-Klasse, und Kenntnis des Unterschiedes Value-/Referenz-Typ ist damit vorrausgesetzt, sonst würde man sich ja garnet wundern über das String-Verhalten.)




      @Rushden: Object.ReferenceEquals ist identisch mit dem VB-Is-Operator

      Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „ErfinderDesRades“ ()

      Es gibt noch eine kleine Falle, die wegen Cmpileroptimierung auftritt.
      Bei diesem Code sind beide Strings referenzgleich, weil der Compiler offensichtlich optimiert und nur ein Objekt erstellt:

      VB.NET-Quellcode

      1. ​Dim s1 = "Hello"
      2. Dim s2 = "Hello"
      3. MessageBox.Show((s1 Is s2).ToString())

      Bei diesem hier aber nicht, da man die Erstellung von zwei verschiedenen Strings erzwingt:

      VB.NET-Quellcode

      1. ​Dim s1 = New String(New Char() {"H"c, "e"c, "l"c, "l"c, "o"c})
      2. Dim s2 = "Hello"
      3. MessageBox.Show((s1 Is s2).ToString())
      Interessant, wenn auch wenig praxisrelevant.
      Also man muss sich wohl merken: Strings vergleicht man mit =, nicht mit Is.
      Ausnahme, wenn man explizit auf Nothing testen, und dabei Nothing von "" unterscheiden will.
      Beispiel

      VB.NET-Quellcode

      1. Using sr = New StreamReader(filePath)
      2. Do
      3. Dim line = sr.ReadLine
      4. If line Is Nothing Then Exit Do
      5. 'was mit der Zeile tun
      6. Loop
      7. End Using