39

I was shocked to find out today that C# does not support dynamic sized arrays. How then does a VB.NET developer used to using ReDim Preserve deal with this in C#?

At the beginning of the function I am not sure of the upper bound of the array. This depends on the rows returned from the database.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
JL.
  • 78,954
  • 126
  • 311
  • 459
  • 17
    I think the other side would say "I am shocked to find out that VB supports dynamically sized arrays." – user7116 Nov 30 '08 at 19:00
  • yeah sixlettervariables, it seems dynamic sized arrays were all too easy to use, but at a serious performance cost. – Michael L Dec 09 '08 at 06:51

7 Answers7

84

VB.NET doesn't have the idea of dynamically sized arrays, either - the CLR doesn't support it.

The equivalent of "Redim Preserve" is Array.Resize<T> - but you must be aware that if there are other references to the original array, they won't be changed at all. For example:

using System;

class Foo
{
    static void Main()
    {
        string[] x = new string[10];
        string[] y = x;

        Array.Resize(ref x, 20);
        Console.WriteLine(x.Length); // Prints out 20
        Console.WriteLine(y.Length); // Still prints out 10
    }
}

Proof that this is the equivalent of Redim Preserve:

Imports System

Class Foo
    Shared Sub Main()
        Dim x(9) as String
        Dim y as String() = x

        Redim Preserve x(19)
        Console.WriteLine(x.Length)
        Console.WriteLine(y.Length)
    End Sub
End Class

The two programs are equivalent.

If you truly want a dynamically sized collection, you should use List<T> (or something similar). There are various issues with using arrays directly - see Eric Lippert's blog post for details. That's not to say you should always avoid them, by any means - but you need to know what you're dealing with.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 7
    There is one difference between the techniques. Array.Resize works only on zero-based single dimensional arrays. Redim works on multi-dimensional arrays. No sure about the zero-based portion – JaredPar Nov 30 '08 at 07:44
  • also worth noting.. and I don't know if it's the case with redim. But worth noting also that with C#, Array.Resize will make the variable point to a new array (as can be seen with Object.ReferenceEquals(..). So y and x now point to two different arrays.. y is no longer an alias for x.. And changing x[0] will no longer change y[0]. and you now have two arrays rather than one. – barlop Mar 01 '16 at 18:20
  • @barlop: Yes, that's precisely what the example demonstrates... and why I wrote: "The equivalent of "Redim Preserve" is Array.Resize - but you must be aware that if there are other references to the original array, they won't be changed at all." – Jon Skeet Mar 01 '16 at 18:22
  • I have always thought (assumed) that if the new size was smaller it would reuse the same memory and just "trim" the excess. Reference Source clearly shows that you will get a new array every time. – Chad Schouggins May 18 '16 at 23:22
  • @ChadSchouggins: Wouldn't it be good if...? Super-efficient shrinking array. – Paul Sep 07 '17 at 11:00
  • @JaredPar: This can be combatted in some ways by multiplying out your multidimensional array into a single dimension, then increasing your array size by orders of magnitude. Not a true solution, I know, but a possibility. – Paul Sep 07 '17 at 11:03
13

Use ArrayLists or Generics instead

Michael L
  • 5,560
  • 7
  • 29
  • 32
  • 9
    More precisely, use List. There are plenty of generic classes or functions in .NET that aren't resizeable arrays. ;) – jalf Nov 29 '08 at 19:52
  • 1
    I would stay away from ArrayLists. Besides being harder to use, Microsoft has said they won't be available on new platforms like Silverlight. – Jonathan Allen Nov 29 '08 at 20:00
  • Silverlight is gone now @JonathanAllen. going to disappear. – Malachi Feb 05 '14 at 19:02
  • 2
    The exact equivalent of ReDim Preserve is [answered](http://stackoverflow.com/a/327958/2040663) by [@JonSkeet](http://stackoverflow.com/users/22656/jon-skeet). – QuantumHive Sep 05 '16 at 10:28
12

Use a List<T>. It will dynamically size as needed.

driis
  • 161,458
  • 45
  • 265
  • 341
6

You really shouldn't be using ReDim, it can be very expensive. I prefer List(Of T), but there are many options in this area.

That said, you had a question and here is your answer.

x = (int[]) Utils.CopyArray((Array) x, new int[10]);
Jonathan Allen
  • 68,373
  • 70
  • 259
  • 447
  • 1
    How do you think that List copes when it needs to resize its internal buffer? It does exactly the same as ReDim Preserve, basically... Why do you think ReDim is expensive, but not List? (List is certainly more convenient in many ways, but they basically need to do the same thing...) – Jon Skeet Nov 29 '08 at 20:17
  • 1
    Jon, Isn't ReDim Preserve adding what we need at the time we ask and List doubling the size as .net thinks it's needed? I would assume this is monitored and doubled when the framework thinks it's optimum to do so and thus less expensive? Thanks! – user10178 Nov 30 '08 at 19:36
  • 1
    We have to put things in context to see the differences between ReDim Preserve (actually Array.Copy) and List. If you’re doing your resizing inside a loop, after a number of iterations, List ends up allocating less memory than ReDim Preserve. That happens because while a new array is created for each loop iteration with Redim Preserve, with List new arrays only are created when the current one does not have space for a new element. – Alfred Myers Aug 17 '09 at 11:54
  • the only one that gave an answer :) – Guy Cohen Oct 04 '21 at 05:15
2

I couldn't help but notice that none of the above answers approach the concept of multidimensional arrays. That being said, here's an example. The array in question is predefined as x.

int[,] temp = new int[newRows, newCols];
int minRows = Math.Min(newRows, x.GetUpperBound(0) + 1);
int minCols = Math.Min(newCols, x.GetUpperBound(1) + 1);
for (int i = 0; i < minRows ; ++i)
     for (int j = 0; j < minCols; ++j)
         temp[i, j] = x[i, j];
x = temp;
Hameer Abbasi
  • 1,292
  • 1
  • 12
  • 34
2

Just for fun, here's one way to use generics in order to redim/extend a unidimensional array (add one more "row") :

static T[] Redim<T>(T[] arr, bool preserved)
{
    int arrLength = arr.Length;
    T[] arrRedimed = new T[arrLength + 1];
    if (preserved)
    {
        for (int i = 0; i < arrLength; i++)
        {
            arrRedimed[i] = arr[i];
        }
    }
    return arrRedimed;
}

And one to add n rows (though this doesn't prevent user from undersizing the array, which will throw an error in the for loop) :

static T[] Redim<T>(T[] arr, bool preserved, int nbRows)
{
    T[] arrRedimed = new T[nbRows];
    if (preserved)
    {
        for (int i = 0; i < arr.Length; i++)
        {
            arrRedimed[i] = arr[i];
        }
    }
    return arrRedimed;
}

I'm sure you get the idea.

For a multidimensional array (two dimensions), here's one possibility:

static T[,] Redim<T>(T[,] arr, bool preserved)
{
    int Ubound0 = arr.GetUpperBound(0);
    int Ubound1 = arr.GetUpperBound(1);
    T[,] arrRedimed = new T[Ubound0 + 1, Ubound1];
    if (preserved)
    {
        for (int j = 0; j < Ubound1; j++)
        {
            for (int i = 0; i < Ubound0; i++)
            {
                arrRedimed[i, j] = arr[i, j];
            }
        }
    }
    return arrRedimed;
}

In your program, use this with or even without the type specified, the compiler will recognize it :

int[] myArr = new int[10];
myArr = Redim<int>(myArr, true);

or

int[] myArr = new int[10];
myArr = Redim(myArr, true);

Not sure if all this is really relevant though. =D Please feel free to correct me or improve my code. ;)

Tete1805
  • 521
  • 4
  • 6
1

Even though it's a long time ago it might help someone looking for a simple solution - I found something great in another forum:

//from Applied Microsoft.NET framework Programming - Jeffrey Richter
public static Array RedimPreserve(Array origArray, Int32 desiredSize)
        {
            System.Type t = origArray.GetType().GetElementType();
            Array newArray = Array.CreateInstance(t, desiredSize);
            Array.Copy(origArray, 0, newArray, 0, Math.Min(origArray.Length, desiredSize));
            return newArray;
        }

Source: https://social.msdn.microsoft.com/Forums/en-US/6759816b-d525-4752-a3c8-9eb5f4a5b194/redim-in-c?forum=csharplanguage

AllDayPiano
  • 414
  • 1
  • 4
  • 20