Rob Garrett - Blogs

Welcome to Rob Garrett - Blogs Sign in | Join | Help
in Search
Google

Software/Technology Discussion

Software and Technology Tid-bits

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.
Share this post: Email it! | bookmark it! | digg it! | reddit!
Published Sunday, January 16, 2005 12:02 AM by Rob Garrett

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

 

Eli Allen said:

In comparing how c# and VB.net does comparisons try looking up:
Option Compare Binary
January 20, 2005 9:05 PM
 

psg said:

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. 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("Software\JCPENNEY\JCPQUEUE\Appl\PS\DALG", 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
June 9, 2008 7:33 PM

Leave a Comment

(required) 
(optional)
(required) 
Submit

Blurb


Head Shot
Rob Garrett is a British Expat living in Maryland USA. Rob is a trained software engineer and experienced in Windows .NET development.

Rob enjoys listening to Rock music, posting to blogs, driving in the country with the sunroof open, beer (not in conjunction with country driving) and spending time with his family.

This Blog

Syndication

Powered by Community Server, by Telligent Systems