Tuesday, September 6, 2011

Creating non zero based arrays in .Net

Last week when I was hunting for .Net performance tips and an array related tip got my attention.It says “Non-zero based arrays will reduce performance”.ie the current default lower bound of .net array is 0.If we change this lower bound of array it will cause performance penalty.But luckily there are no places in our project where developers used non-zero based arrays. I should say thanks to .Net architects in Microsoft than our developers, for making the creation of non-zero based arrays bit complicated. According to my current knowledge, using the normal declaration syntax of array, its not possible to create non-zero based arrays. The only way now is to use the Array.CreateInstance method.Look at the below code snippet.

Array arrayObject = Array.CreateInstance(typeof(int), new int[] { 5 }, new int[] { 2 });



This creates single dimension integer array of size 5 with lower bound as 2.ie you need to access the array as arrayObject[2] to [6] not arrayObject[0].



Normal array and Array.CreateInstance


As you know all the arrays are of class type Array which gives them the ability of iteration and all. We can create array using the CreateInstance method, just like how we create normal array with square bracket.If we display the type of Array object we can see its exactly same as the type of normal array object with [].We can cast the output to normal array object and access the elements using [].Look at the below code it just creates an array with zero as lower bound and access the element at position 0.




private void TestBase0Array()
{
Array arrayObject=Array.CreateInstance(typeof(int), new int[] { 5 }, new int[] { 0 });
int[] intArray = arrayObject as int[];
if (intArray != null)
{
Console.WriteLine("TestBase0Array(): ArrayCreateInstance() succeded for base 0, Array type :" + intArray.GetType().FullName);
try
{
intArray[0] = 10;
Console.WriteLine("TestBase0Array():Write & Read from array [0] - " + intArray[0]);
}
catch (Exception ex)
{
Console.WriteLine("TestBase0Array():Not able to access array");
}
}
else
Console.WriteLine("TestBase0Array(): Not able cast to int[]");
}



Type of non-zero based arrays


When we come to arrays who’s lower bound is not zero, the type will be different. it will contain a ‘*’.If its an integer array the type will be ‘System.Int32[*]’. This means we cannot cast the output of Array.CreateInstance to our normal array object which is declared using [].(But I am not sure whether there are any hidden methods to cast to normal array).So we cannot access the array elements using [].Then the final option is to use the SetValue and GetValue methods of Array class.Look at the below code.




private void TestBase2Array()
{
Array arrayObject=Array.CreateInstance(typeof(int), new int[] { 5 }, new int[] { 2 });
int[] intArray = arrayObject as int[];
if (intArray != null)
{
Console.WriteLine("TestBase2Array(): ArrayCreateInstance() succeded for base 0, Array type :" + intArray.GetType().FullName);
try
{
intArray[0] = 10;
Console.WriteLine("TestBase2Array():Write & Read from array [0] - " + intArray[0]);
}
catch (Exception ex)
{
Console.WriteLine("TestBase2Array():Not able to access array using []");
}
}
else
{
Console.WriteLine("TestBase2Array(): Not able cast to int[].Array Type :"+arrayObject.ToString());
Console.WriteLine("TestBase2Array(): Lower bound :" + arrayObject.GetLowerBound(0).ToString());
Console.WriteLine("TestBase2Array(): Length :" + arrayObject.Length.ToString());

try
{
arrayObject.SetValue(10, 0);
Console.WriteLine ("TestBase2Array(): Element at 0"+ arrayObject.GetValue(10, 0).ToString());
}
catch (Exception ex)
{
Console.WriteLine("TestBase2Array(): Not able to access element at 0.Trying 2nd element");
arrayObject.SetValue(10, 2);
Console.WriteLine("TestBase2Array(): Element at "+arrayObject.GetValue(2).ToString());
}
}
}



dynamic keyword and non-zero based arrays


Its really difficult to use 2 methods to access an array for a developer who would like to access the array as it is.So I tried assigning the output of Array.CreateInstance to a dynamic variable and used the square brackets.It never gives a compilation error.But at runtime it fails with an exception “Unable to cast object of type 'System.Int32[*]' to type 'System.Int32[]'”.




private void TestBase2ArrayUsingDynamic()
{
Array arrayObject = Array.CreateInstance(typeof(int), new int[] { 5 }, new int[] { 2 });
dynamic intArray = arrayObject;
try
{
intArray[2] = 10;
Console.WriteLine("TestBase1ArrayUsingDynamic():Write & Read from array [0] using dynamic keyword- " + intArray[2]);
}
catch (Exception ex)
{
Console.WriteLine("TestBase1ArrayUsingDynamic():Exception :"+ ex.Message +
Environment.NewLine + "Not able to access non zero based array even using dynamic keyword!!!");
}
}


That means dynamic keyword also failed. We need to use the SetValue and GetValue if we want to use non-zero based arrays.

Non-Zero based arrays and VB.Net


But in VB.Net the story is different.If you are working in VB.Net its all easy.You can use non-zero based arrays in the normal array. I don’t know whether it’s the beauty or curse of unsafe programming.




Dim arrayObject = Array.CreateInstance(GetType(Integer), New Integer() {5}, New Integer() {2})
arrayObject(2) = 10
Console.WriteLine(arrayObject(2).ToString)



I don’t think we need to use non-zero based arrays in any of the situations of our normal programming life. One more thing is this non-zero based array creation is not supported by Silverlight. That means if you are developing in common code base which is targeted for WPF,Silverlight and WP7 you will not encounter this scenario.

No comments: