DekGenius.com
[ Team LiB ] Previous Section Next Section

Recipe 16.7 Creating and Using an Array of Pointersto Unknown Types

Problem

You need to create and operate on elements of an array that holds objects of unknown types.

Solution

The solution is to create an array of void pointers so that we do not need to know at design time what type(s) we will be pointing to:

unsafe
{
    long x = 10;
    long y = 20;
    long z = 1;

    void*[] arrayOfPtrs = new void*[3];
    arrayOfPtrs[0] = &X;
    arrayOfPtrs[1] = &Y;
    arrayOfPtrs[2] = &Z;

    Console.WriteLine(*((long*)arrayOfPtrs[0]));
    Console.WriteLine(*((long*)arrayOfPtrs[1]));
    Console.WriteLine(*((long*)arrayOfPtrs[2]));
}

This code creates an array, arrayOfPtrs, that will contain three void pointers. The pointers that are saved to this array are pointers to the three variables x, y, and z of type long. It is a simple matter to change the long data type to something different such as a byte or char. However, when the pointers in this array are used, they must be cast back to their original type. This cast is shown in the last three lines, where each pointer in the array is being dereferenced and displayed. If you do the wrong cast, you get undefined results, but the next example helps address this.

The following code creates an array of two void pointers and points the first pointer at a NewBrush structure and the second at an integer type variable:

unsafe
{
    NewBrush theNewBrush1 = new NewBrush( );
    int* theInt = stackalloc int[1];

    void*[] arrayOfPtrs = new void*[2];

    arrayOfPtrs[0] = &theNewBrush1;
    arrayOfPtrs[1] = theInt;

    Console.WriteLine("arrayOfPtrs[0] = " + (
                      (NewBrush*)arrayOfPtrs[0])->BrushType);
    Console.WriteLine("arrayOfPtrs[1] = " + 
                      ((int*)arrayOfPtrs[1])->ToString( ));
}

This code starts by creating a new NewBrush structure and a new pointer to an integer and the integer itself on the stack using the stackalloc statement. Next, the array of void pointers is created. At this point, we could opt to set all of the void pointers to null, but here we will immediately initialize each void pointer in the array to point to one of the previously declared types. However, this solution presents a problem with casting the pointers in the array back to their original types. This solution requires you to keep track of the data type that is stored in each element of the array so that you can correctly cast it back to its original type.

Discussion

Notice that each of the pointers in the array must be cast to their proper pointer type before the value they point to can be used, as shown in the following code:

((NewBrush*)arrayOfPtrs[0])->BrushType = 5;
*((int*)arrayOfPtrs[1]) = 111;

We cannot simply write *arrayOfPtrs[0] to dereference the pointer at the first element of the array. The compiler cannot accurately determine what type to dereference it as. Therefore the array element must be cast to some type before it is dereferenced.

When you cast a void pointer to an incorrect type, an exception will never be thrown. Using this incorrectly cast pointer can result in corruption of the original data that the pointer pointed to. This is one of the things that makes unsafe code so unsafe to use.

See Also

See the "Void Sample" article and the "stackalloc" keyword in the MSDN documentation.

    [ Team LiB ] Previous Section Next Section