Mar 16 2006

Code conversion pitfalls

Category: .Net | IT RelatedRory Primrose @ 18:06

After doing four days of training and meetings in Brisbane, I am now back in the office reviewing some code. I had originally developed some web custom controls in VB (the organisations language of choice) that were then put into an architecture framework. This required that the code be converted from VB to C# which is the language of the framework involved. This work was done by another person while I was back in my prior UI design team.

Doing a code review of C# that is based on my VB code has put me in a new situation. Not having done this before, I am trying to think of scenarios that look safe, but are trouble under the surface. Turns out I found one very quickly. In this case, string comparisons are the danger. The VB code often had statements like this:

If sSomeValue = String.Empty Then

    ' Do something here

End If

VB is very forgiving with its string comparisons and it attempts to cover all the possibilities. If a straight language conversion is done, the same result does not occur in C#. To test this, I came up with a program in VB and in C#.

Here is the VB version of the program:

Public Class Form1 
  
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click 
  
        RunTests("""""", "") 
        RunTests("String.Empty", String.Empty) 
        RunTests("Nothing", Nothing) 
        RunTests("ThisValue", "ThisValue") 
  
    End Sub 
  
    Private Sub RunTests(ByVal sTestName As String, ByVal sTest As String) 
  
        Debug.WriteLine(New String("_"c, 50)) 
        Debug.WriteLine(String.Empty) 
        Debug.WriteLine("Testing string value " & sTestName) 
        Debug.WriteLine(String.Empty) 
  
        If (sTest = "") Then 
            Debug.WriteLine("Success: " & sTestName & " is equal to """"") 
        Else 
            Debug.WriteLine("Failed: " & sTestName & " is not equal to """"") 
        End If 
  
        If (sTest = Nothing) Then 
            Debug.WriteLine("Success: " & sTestName & " is equal to Nothing") 
        Else 
            Debug.WriteLine("Failed: " & sTestName & " is not equal to Nothing") 
        End If 
  
        If (sTest = String.Empty) Then 
            Debug.WriteLine("Success: " & sTestName & " is equal to String.Empty") 
        Else 
            Debug.WriteLine("Failed: " & sTestName & " is not equal to String.Empty") 
        End If 
  
        If String.IsNullOrEmpty(sTest) = True Then 
            Debug.WriteLine("Success: IsNullOrEmpty returns true for " & sTestName) 
        Else 
            Debug.WriteLine("Failed: IsNullOrEmpty returns false for " & sTestName) 
        End If 
  
    End Sub 
  
End Class 

I have missed out a test using vbNullString because it gets compiled as Nothing which is tested.

When this program is run, these are the results:

__________________________________________________

 

Testing string value ""

 

Success: "" is equal to ""

Success: "" is equal to Nothing

Success: "" is equal to String.Empty

Success: IsNullOrEmpty returns true for ""

__________________________________________________

 

Testing string value String.Empty

 

Success: String.Empty is equal to ""

Success: String.Empty is equal to Nothing

Success: String.Empty is equal to String.Empty

Success: IsNullOrEmpty returns true for String.Empty

__________________________________________________

 

Testing string value Nothing

 

Success: Nothing is equal to ""

Success: Nothing is equal to Nothing

Success: Nothing is equal to String.Empty

Success: IsNullOrEmpty returns true for Nothing

__________________________________________________

 

Testing string value ThisValue

 

Failed: ThisValue is not equal to ""

Failed: ThisValue is not equal to Nothing

Failed: ThisValue is not equal to String.Empty

Failed: IsNullOrEmpty returns false for ThisValue

VB has successfully evaluated whether a string has a value or not, regardless of whether the empty value is defined as a literal empty string, String.Empty or Nothing/vbNullString.

Here is the C# version of the program:

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Diagnostics; 
using System.Drawing; 
using System.Text; 
using System.Windows.Forms; 
  
namespace WindowsApplication1 
{ 
    public partial class Form1 : Form 
    { 
        public Form1() 
        { 
            InitializeComponent(); 
        } 
  
        private void button1_Click(object sender, EventArgs e) 
        { 
            RunTests("\"\"", ""); 
            RunTests("String.Empty", String.Empty); 
            RunTests("Nothing", null); 
            RunTests("ThisValue", "ThisValue"); 
        } 
  
        private void RunTests(String sTestName, String sTest) 
        { 
            Debug.WriteLine(new String('_', 50)); 
            Debug.WriteLine(String.Empty); 
            Debug.WriteLine("Testing string value " + sTestName); 
            Debug.WriteLine(String.Empty); 
  
            if (sTest == "") 
            { 
                Debug.WriteLine("Success: " + sTestName + " is equal to \"\""); 
            } 
            else 
            { 
                Debug.WriteLine("Failed: " + sTestName + " is not equal to \"\""); 
            } 
  
            if (sTest == null) 
            { 
                Debug.WriteLine("Success: " + sTestName + " is equal to null"); 
            } 
            else 
            { 
                Debug.WriteLine("Failed: " + sTestName + " is not equal to null"); 
            } 
  
            if (sTest == String.Empty) 
            { 
                Debug.WriteLine("Success: " + sTestName + " is equal to String.Empty"); 
            } 
            else 
            { 
                Debug.WriteLine("Failed: " + sTestName + " is not equal to String.Empty"); 
            } 
  
            if (String.IsNullOrEmpty(sTest) == true) 
            { 
                Debug.WriteLine("Success: IsNullOrEmpty returns true for " + sTestName); 
            } 
            else 
            { 
                Debug.WriteLine("Failed: IsNullOrEmpty returns false for " + sTestName); 
            } 
        } 
    } 
} 

When this program is run, these are the results:

__________________________________________________

 

Testing string value ""

 

Success: "" is equal to ""

Failed: "" is not equal to null

Success: "" is equal to String.Empty

Success: IsNullOrEmpty returns true for ""

__________________________________________________

 

Testing string value String.Empty

 

Success: String.Empty is equal to ""

Failed: String.Empty is not equal to null

Success: String.Empty is equal to String.Empty

Success: IsNullOrEmpty returns true for String.Empty

__________________________________________________

 

Testing string value Nothing

 

Failed: Nothing is not equal to ""

Success: Nothing is equal to null

Failed: Nothing is not equal to String.Empty

Success: IsNullOrEmpty returns true for Nothing

__________________________________________________

 

Testing string value ThisValue

 

Failed: ThisValue is not equal to ""

Failed: ThisValue is not equal to null

Failed: ThisValue is not equal to String.Empty

Failed: IsNullOrEmpty returns false for ThisValue

Definately a different result. The reason for the difference is how the VB and C# code has been compiled down to IL.

Reflector shows the following for the VB program:

Private Sub RunTests(ByVal sTestName As String, ByVal sTest As String)

    Debug.WriteLine(New String("_"c, 50))
    Debug.WriteLine(String.Empty)
    Debug.WriteLine(("Testing string value " & sTestName))
    Debug.WriteLine(String.Empty)

    If (Operators.CompareString(sTest, "", False) = 0) Then
        Debug.WriteLine(("Success: " & sTestName & " is equal to """""))
    Else
        Debug.WriteLine(("Failed: " & sTestName & " is not equal to """""))
    End If

    If (Operators.CompareString(sTest, Nothing, False) = 0) Then
        Debug.WriteLine(("Success: " & sTestName & " is equal to Nothing"))
    Else
        Debug.WriteLine(("Failed: " & sTestName & " is not equal to Nothing"))
    End If

    If (Operators.CompareString(sTest, String.Empty, False) = 0) Then
        Debug.WriteLine(("Success: " & sTestName & " is equal to String.Empty"))
    Else
        Debug.WriteLine(("Failed: " & sTestName & " is not equal to String.Empty"))
    End If

    If String.IsNullOrEmpty(sTest) Then
        Debug.WriteLine(("Success: IsNullOrEmpty returns true for " & sTestName))
    Else
        Debug.WriteLine(("Failed: IsNullOrEmpty returns false for " & sTestName))
    End If

End Sub

Reflector shows the following for the C# program:

private void RunTests(string sTestName, string sTest)
{
    Debug.WriteLine(new string('_', 50));
    Debug.WriteLine(string.Empty);
    Debug.WriteLine("Testing string value " + sTestName);
    Debug.WriteLine(string.Empty);

    if (sTest == "")
    {
        Debug.WriteLine("Success: " + sTestName + " is equal to \"\"");
    }
    else
    {
        Debug.WriteLine("Failed: " + sTestName + " is not equal to \"\"");
    }

    if (sTest == null)
    {
        Debug.WriteLine("Success: " + sTestName + " is equal to null");
    }
    else
    {
        Debug.WriteLine("Failed: " + sTestName + " is not equal to null");
    }

    if (sTest == string.Empty)
    {
        Debug.WriteLine("Success: " + sTestName + " is equal to String.Empty");
    }
    else
    {
        Debug.WriteLine("Failed: " + sTestName + " is not equal to String.Empty");
    }

    if (string.IsNullOrEmpty(sTest))
    {
        Debug.WriteLine("Success: IsNullOrEmpty returns true for " + sTestName);
    }
    else
    {
        Debug.WriteLine("Failed: IsNullOrEmpty returns false for " + sTestName);
    }
}
The outcome of this is that for the "same" code to behave the same across both languages, using String.IsNullOrEmpty() is the safest way of determining whether a string as a value.

Tags:

Add comment


(Will show your Gravatar icon)

  Country flag

biuquote
  • Comment
  • Preview
Loading