Redim Preserve in C#?
Asked Answered
G

7

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.

Giacopo answered 29/11, 2008 at 19:44 Comment(2)
I think the other side would say "I am shocked to find out that VB supports dynamically sized arrays."Marlite
yeah sixlettervariables, it seems dynamic sized arrays were all too easy to use, but at a serious performance cost.Divergent
D
13

Use ArrayLists or Generics instead

Divergent answered 29/11, 2008 at 19:47 Comment(4)
More precisely, use List<T>. There are plenty of generic classes or functions in .NET that aren't resizeable arrays. ;)Unattended
I would stay away from ArrayLists. Besides being harder to use, Microsoft has said they won't be available on new platforms like Silverlight.Beiderbecke
Silverlight is gone now @JonathanAllen. going to disappear.Euraeurasia
The exact equivalent of ReDim Preserve is answered by @JonSkeet.Kiri
G
83

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.

Ghyll answered 29/11, 2008 at 20:12 Comment(6)
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 portionTysontyumen
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.Llamas
@barlop: Yes, that's precisely what the example demonstrates... and why I wrote: "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."Ghyll
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.Penury
@ChadSchouggins: Wouldn't it be good if...? Super-efficient shrinking array.Innervate
@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.Innervate
D
13

Use ArrayLists or Generics instead

Divergent answered 29/11, 2008 at 19:47 Comment(4)
More precisely, use List<T>. There are plenty of generic classes or functions in .NET that aren't resizeable arrays. ;)Unattended
I would stay away from ArrayLists. Besides being harder to use, Microsoft has said they won't be available on new platforms like Silverlight.Beiderbecke
Silverlight is gone now @JonathanAllen. going to disappear.Euraeurasia
The exact equivalent of ReDim Preserve is answered by @JonSkeet.Kiri
B
12

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

Bellflower answered 29/11, 2008 at 19:46 Comment(1)
@Marlite never ? why and reasons ?Postmortem
B
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]);
Beiderbecke answered 29/11, 2008 at 19:58 Comment(4)
How do you think that List<T> 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<T>? (List<T> is certainly more convenient in many ways, but they basically need to do the same thing...)Ghyll
Jon, Isn't ReDim Preserve adding what we need at the time we ask and List<T> 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!Lucas
We have to put things in context to see the differences between ReDim Preserve (actually Array.Copy) and List<T>. If you’re doing your resizing inside a loop, after a number of iterations, List<T> 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<T> new arrays only are created when the current one does not have space for a new element.Dittmer
the only one that gave an answer :)Sonnysonobuoy
G
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;
Gap answered 18/11, 2012 at 3:42 Comment(0)
A
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. ;)

Anon answered 18/12, 2013 at 18:28 Comment(0)
F
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

Fasano answered 12/11, 2015 at 6:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.