More on Null and Empty Strings

Following on from Jeff Atwood’s post
about comparing a string to empty string (“”), I found out that C# and
VB.net do not behave the same when comparing a string that is null.

In the following C# snippet, the code will display The String is NOT Null:

string s = null;
if (s == “”)
  Console.WriteLine(“The String IS Null”);
else
  Console.WriteLine(“The String is NOT Null”);

The following VB.net code will display The String IS Null:

Dim s as string = Nothing
If s = “” Then
  Console.WriteLine(“The String IS Null”)

else

  Console.WriteLine(“The String is NOT Null”)
End If

The IL for the C# code is:

.method private hidebysig static void
            Main(string[] args) cil managed
    {
      .entrypoint
      .custom instance void [mscorlib]System.STAThreadAttribute::.ctor()
        = ( 01 00 00 00 )
      // Code size       38 (0x26)
      .maxstack  2
      .locals init (string V_0)
      IL_0000:  ldnull
      IL_0001:  stloc.0
      IL_0002:  ldloc.0
      IL_0003:  ldstr      “”
      IL_0008: 
call       bool
[mscorlib]System.String::op_Equality(string,string)
      IL_000d:  brfalse.s  IL_001b

      IL_000f:  ldstr      “The String IS Null”
      IL_0014: 
call       void
[mscorlib]System.Console::WriteLine(string)
      IL_0019:  br.s       IL_0025

      IL_001b:  ldstr      “The String is NOT Null”
      IL_0020: 
call       void
[mscorlib]System.Console::WriteLine(string)
      IL_0025:  ret
    } // end of method Class1::Main

The IL for the VB.net code is:

.method public static void  Main() cil managed
    {
      .entrypoint
      .custom instance void [mscorlib]System.STAThreadAttribute::.ctor() =
        ( 01 00 00 00 )
      // Code size       46 (0x2e)
      .maxstack  3
      .locals init ([0] string s)
      IL_0000:  nop
      IL_0001:  ldnull
      IL_0002:  stloc.0
      IL_0003:  ldloc.0
      IL_0004:  ldstr      “”
      IL_0009:  ldc.i4.0
      IL_000a: 
call       int32

       [Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.
   StringType::StrCmp(string,string,bool)
      IL_000f:  ldc.i4.0
      IL_0010:  bne.un.s   IL_001f

      IL_0012:  ldstr      “The String IS Null”
      IL_0017: 
call       void
[mscorlib]System.Console::WriteLine(string)
      IL_001c:  nop
      IL_001d:  br.s       IL_002b

      IL_001f:  nop
      IL_0020:  ldstr      “The String is NOT Null”
      IL_0025: 
call       void
[mscorlib]System.Console::WriteLine(string)
      IL_002a:  nop
      IL_002b:  nop
      IL_002c:  nop
      IL_002d:  ret
    } // end of method Module1::Main

As we can see from the VB.net IL, the string comparison is replaced
with a call to
Microsoft.VisualBasic.CompilerServices.StringType::StrCmp. From further
reading I understand that Microsoft did this to maintain compatibility
with VB6. The C# compiler on the other hand uses op_Equality to check
the equality of empty string and null. Since null and empty string are
not equal C# returns false from the condition.

So, the debate about whether to use S == “”
or not just about performance, but also about expected operational
behavior. Developers who switch between C# and VB.net could find some
unexpected results in their software if they are not aware of this
idiosyncrasy.

Going back to performance…. Chris Taylor has some nice graphs on
his blog, which show the significant differences in time between S1 == S2, S1.op_Equality(S1), S1.Equals(S1) and String.Equals(S1, S2). Performance varied by test but S1.op_Equality(S1) seemed to be an overall god performer, which is real handy because it’s what the C# compiler chooses when optimizing S1 == S2.

As much as I hate to see code, which doesn’t read as one would expect, VB.net programmers might want to consider using String.Equals(S1, S2) or S1.Length > 0 when doing lots of string comparisons.

In both C# and VB.net worlds, it’s good development practice to check
your strings against null before performing equality operations. Never
assume the compiler is always going to do the work for you – oh it
brings me back to my C++ days when the compiler did crap for you.

2 thoughts on “More on Null and Empty Strings

  1. http://

    Can you help me with my code.I am creating a dynamic table with radiobuttons. I am also storing the radiobutton values in an array.But i am not able to get the selected id of a radiobutton to go to the next page.appreciate your time and help

    Option Explicit On
    Imports System
    Imports Microsoft.Win32
    Imports System.Web.UI.WebControls.TableCell
    Imports System.Web.UI.WebControls.RadioButton
    Imports System.Web.UI.WebControls.ListBox

    Public Class WebForm2
    Inherits System.Web.UI.Page

    #Region ” Web Form Designer Generated Code ”

    ‘This call is required by the Web Form Designer.
    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()

    End Sub
    Protected WithEvents Label1 As System.Web.UI.WebControls.Label
    Protected WithEvents DataGrid1 As System.Web.UI.WebControls.DataGrid
    Protected WithEvents DataGrid2 As System.Web.UI.WebControls.DataGrid
    Protected WithEvents Button1 As System.Web.UI.WebControls.Button
    Protected WithEvents dt As System.Web.UI.WebControls.Table

    ‘NOTE: The following placeholder declaration is required by the Web Form Designer.
    ‘Do not delete or move it.
    Private designerPlaceholderDeclaration As System.Object

    Private Sub Page_Init(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Init
    ‘CODEGEN: This method call is required by the Web Form Designer
    ‘Do not modify it using the code editor.
    InitializeComponent()
    End Sub

    #End Region

    Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    Dim regKey2 As RegistryKey
    Dim regkey1 As RegistryKey
    Dim Str1, Str2, Str3, Strres As String
    Dim i, value1, value2, value3
    Dim StringResult As String
    Str1 = “S501”
    Str3 = “SRS002”
    For i = 1 To 8
    Dim radMachines As New RadioButton
    Dim item, ch As String
    radMachines.ID = “rbl_” & i
    radMachines.GroupName = “storeinfo”
    ‘radMachines.Checked = True
    ‘radMachines.AutoPostBack = True
    item = radMachines.ID.ToString
    ch = “|”
    StringResult = String.Concat(item, ch)
    Dim drow2 As New TableRow
    Dim ps0 As New TableCell
    Dim ps1 As New TableCell
    Dim ps2 As New TableCell
    Dim ps3 As New TableCell
    Dim ps4 As New TableCell
    Dim strtry As String
    regkey1 = Registry.LocalMachine.OpenRemoteBaseKey(RegistryHive.LocalMachine, String.Concat(Str1, i, Str3))
    regKey2 = regkey1.OpenSubKey(“SoftwareJCPENNEYJCPQUEUEApplPSDALG”, True)
    Strres = String.Concat(Str1, i, Str3)
    value1 = regKey2.GetValue(“PSQueueName”)
    value2 = regKey2.GetValue(“RecvQMName”)
    value3 = regKey2.GetValue(“SendQMName”)
    ps0.Controls.Add(radMachines)
    ps1.Controls.Add(New LiteralControl(Strres))
    ps2.Controls.Add(New LiteralControl(value1))
    ps3.Controls.Add(New LiteralControl(value2))
    ps4.Controls.Add(New LiteralControl(value3))
    drow2.Cells.Add(ps0)
    drow2.Cells.Add(ps1)
    drow2.Cells.Add(ps2)
    drow2.Cells.Add(ps3)
    drow2.Cells.Add(ps4)
    dt.Rows.Add(drow2)
    ‘Response.Write(StringResult)

    ‘Need help after this line.
    Dim a(8) As String
    Dim Str = “”
    Dim j As Integer
    a = StringResult.Split(“|”)
    ‘For j = 1 To j = 8
    If Page.IsPostBack = True Then
    If Request.Params(radMachines.ID.ToString) <> Nothing Then
    Str = Request.Params(radMachines.ID.ToString)
    If a(1) = Str Then
    Response.Write(a(1))
    End If
    ‘ElseIf Request.Params(a(1)) <> Nothing Then
    ‘Response.Write(a(1))
    ‘ElseIf Request.Params(a(2)) <> Nothing Then
    ‘Response.Write(a(2))

    End If

    End If
    Next
    ‘Controls.Add(radMachines)
    ‘Dim Str
    ‘If Page.IsPostBack Then
    ‘Str = Request.Params(radMachines.Checked.ToString)
    ‘End If
    ‘Response.Write(StringResult)
    regkey1.Close()
    regKey2.Close()
    End Sub

    End Class

Comments are closed.