Jakub Arnold Jakub Arnold - 2 months ago 18
C# Question

Is there a List<T> like dynamic array that allows access to the internal array data in .NET?

Looking over the source of

List<T>
, it seems that there's no good way to access the private
_items
array of items.

What I need is basically a dynamic list of
struct
s, which I can then modify in place. From my understanding, because C# 6 doesn't yet support
ref
return types, you can't have a
List<T>
return a reference to an element, which requires copying of the whole item, for example:

struct A {
public int X;
}

void Foo() {
var list = new List<A> { new A { X = 3; } };

list[0].X++; // this fails to compile, because the indexer returns a copy

// a proper way to do this would be
var copy = list[0];
copy.X++;
list[0] = copy;


var array = new A[] { new A { X = 3; } };

array[0].X++; // this works just fine
}


Looking at this, it's both clunky from syntax point of view, and possibly much slower than modifying the data in place (Unless the JIT can do some magic optimizations for this specific case? But I doubt they could be relied on in the general case, unless it's a special standardized optimization?)

Now if
List<T>._items
was protected, one could at least subclass
List<T>
and create a data structure with specific modify operations available. Is there another data structure in .NET that allows this, or do I have to implement my own dynamic array?

EDIT: I do not want any form of boxing or introducing any form of reference semantics. This code is intended for very high performance, and the reason I'm using an array of structs is to have them tighly packed on memory (and not everywhere around heap, resulting in cache misses).

I want to modify the structs in place because it's part of a performance critical algorithm that stores some of it's data in those structs.

Answer

Is there another data structure in .NET that allows this, or do I have to implement my own dynamic array?

Neither.

There isn't, and can't be, a data structure in .NET that avoids the structure copy, because deep integration with the C# language is needed to get around the "indexed getter makes a copy" issue. So you're right to think in terms of directly accessing the array.

But you don't have to build your own dynamic array from scratch. Many List<T>-like operations such as Resize and bulk movement of items are provided for you as static methods on type System.Array. They come in generic flavors, so no boxing is involved.

The unfortunate thing is that the high-performance Buffer.BlockCopy, which should work on any blittable type, actually contains a hard-coded check for primitive types and refuses to work on any structure.

So just go with T[] (plus int Count -- array length isn't good enough because trying to keep capacity equal to count is very inefficient) and use System.Array static methods when you would otherwise use methods of List<T>. If you wrap this as a PublicList<T> class, you can get reusability and both the convenience of methods for Add, Insert, Sort as well as direct element access by indexing directly on the array. Just exercise some restraint and never store the handle to the internal array, because it will become out-of-date the next time the list needs to grow its capacity. Immediate direct access is perfectly fine though.