GOTCHA #34 Defining an array isn't consistentMost of the application code I write is in C#. However, I have been involved in a few projects where I had to mix languages and write some VB.NET code. The fact that the .NET Framework class library (FCL) is the same for C# and VB.NET gives me the confidence that I can switch between the languages with maximum ease. But my confidence has been shaken when I have come across code that looks correct but doesn't work the way I expect it to. When dealing with arrays, quite a bit of confusion is inherited from the earlier languages. While C-derived languages have zero-based indexes, VB6 used one-based indexes. However, in VB.NET, the index is zero-based. Well, can you say that all .NET languages are consistent now? Suppose you are a C# developer and you write the code in Example 4-9. Example 4-9. Array allocationC# and VB.NET (Array) //Test.cs part of C# project Iterateover.exe using System; namespace IterateOver { class Test { [STAThread] static void Main(string[] args) { object[] objects = new object[3]; for(int i = 0; i < 3; i++) { objects[i] = new object(); } foreach(Object anObj in objects) { Console.WriteLine(anObj.GetHashCode()); } } } } You create an array of objects and set each element to an object instance. Then you use foreach to traverse the array and print the hash code of each object. The output is shown in Figure 4-8. Figure 4-8. Output from Example 4-9Now suppose you are asked to convert this code to VB.NET. That shouldn't be too difficult, right? So, here you go, your VB.NET version of the above code is shown in Example 4-10. Example 4-10. VB.NET version of Example 4-9C# and VB.NET (Array) 'Test.vb - VB.NET Port of Test.cs Module Test Sub Main() Dim objects() As Object = New Object(3) {} For i As Integer = 0 To 2 objects(i) = New Object Next For Each anObj As Object In objects Console.WriteLine(anObj.GetHashCode()) Next End Sub End Module That's a straightforward port. You changed the syntax from C# to the appropriate syntax in VB.NET. But when you execute the VB.NET code, you get the output shown in Figure 4-9. Figure 4-9. Output from Example 4-10What went wrong? It first printed the hash code for the three objects as you would expect, and then it threw a NullReferenceException. The reason for this problem is that, in VB.NET, when you declared new Object(3) {}, you actually created an array of size 4 instead of size 3. Consider the code in Example 4-11. Example 4-11. Array size differencesC# and VB.NET (Array) //MyCollection.cs part of CSLib.dll using System; namespace CSLib { public class MyCollection { public int[] Values { get { return new int[10]; } } } } 'MyCollection.vb part of VBLib.dll Public Class MyCollection Public ReadOnly Property Values() Get Return New Integer(10) {} End Get End Property End Class 'TestModule.vb in VBUser.exe Module TestModule Sub Main() Dim obj1 As New CSLib.MyCollection Dim obj2 As New VBLib.MyCollection Console.WriteLine("Size of arrays") Console.WriteLine("C# created: {0}", obj1.Values.Length) Console.WriteLine("VB.NET created: {0}", obj2.Values.Length) End Sub End Module In C# you create an array using the syntax new int[10], while in VB.NET you use new int(10) {}. It looks like you're doing the same thing in both, but when you run the program you get the output shown in Figure 4-10. Figure 4-10. Output from Example 4-11Here's the crux of the problem: when you create an array in VB.NET, you specify the maximum index value. In C#, you specify the maximum size (one more than the maximum index value). IN A NUTSHELLUse caution creating arrays, and know the difference in how C# and VB.NET declare them. In C#, you specify the maximum size of the array. In VB.NET, you specify the maximum allowed index value. SEE ALSOGotcha #31, "Optional parameters break interoperability" and Gotcha #33, "Name collision with keywords breaks interoperability." |