5

See also:

Both of those questions are different in that they ask HOW you would change the size, to which I'm well aware that the answer is: "Don't ... use a list". They also reference a ref-based Array.Resize(ref array, int size).

My question is this:

Given that I have a monolithic legacy codebase, that I can't possibly examine the entirety of, and can't make any guarantees of what it does, ... if I have call method passing in a not-by-ref array, can I be guaranteed that the size of the array afterwards is unchanged.

Array.Resize isn't an issue, since the by-ref-ness would have to pass all the way up through the call stack, which it obviously doesn't.

But are there any other possible issues?

REMARKS ON NOT BEING A DUPLICATE

I'd argue that this is a different question from the others, because this is an "Is it possible?" rather than "how would I do it/what's the best way to do it". Thus answers that would be evil and wrong and would not be mentioned in the latter, would still be relevant to my question.

Community
  • 1
  • 1
Brondahl
  • 7,402
  • 5
  • 45
  • 74

2 Answers2

20

can I be guaranteed that the size of the array afterwards is unchanged.

Yes, because arrays never change size. Ever. Array.Resize creates a new array and copies the data; it does not actually resize anything. If you have a reference to the old array, then: you're fine and the size is unchanging.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
1

It is not possible for the array to change size.

  1. Managed arrays never change in size:

An array in C# is a "managed array", which is allocated by the GC on the managed heap. In Managed C++, you'd write [1]:

array<N*>^ arr = gcnew array<N*>(3);

This is a single atomic object from the point of view of the Managed Heap, and it cannot be resized, only used and eventually Garbage Collected. There is no gcresize or gc-re-new operator in managed C++ [2], as this is forbidden in the CLR. It would significantly complicate the managed GC if managed objects could change in size over their lifetime. I have not been able to find a definitive doc cite for this assertion, but I'm reasonably confident.

You might ask how the "Array.Resize" method works, if arrays never change in size. As the docs explain:

This method allocates a new array with the specified size, copies elements from the old array to the new one, and then replaces the old array with the new one.

The Array.Resize method then updates the array typed variable to point at the new array (because the variable is pass-by-ref), and allows the old array to be GC'ed (unless there is another ref to it).

  1. Method arguments in C# are pass-by-val

... so if you don't use any other by-ref methods, no-one can update your array typed variable to point to a different array.

I believe that 1 and 2 together answer your question.

How does that differ from a List?

A List can change in size, without using a by-ref method. That is a bit different. The List object itself is on the managed heap and never changes in size, but it contains a pointer to an array as a member variable. When the List grows, that pointer is updated to point to a longer array containing the new elements.

Rich
  • 15,048
  • 2
  • 66
  • 119