5

I'm refactoring a library we currently use, and I'm faced with the following problem.

We used to have the following stuff :

class Blah
{
    float[][] data;
    public float[] GetDataReference(int index)
    {
        return data[index];
    }
}

For various reasons, I have replaced this jagged array version with a 1 dimensionnal array version, concatenating inner arrays. My question is : how can I still return a reference to a sub array of data ?

class Blah
{
    float[] data;
    int rows;

    public float[] GetDataReference(int index)
    {
        // Return a reference data from offset i to offset j;
    }
}

I was thinking that unsafe and pointers stuff may be of use, is it doable ?

Wam
  • 810
  • 1
  • 8
  • 19

2 Answers2

10

No, you can't do this - but you should look at using ArraySegment instead.

Note that an array object consists of metadata about its length etc and then the data itself. You can't create a slice of an existing array and still have the metadata next to the data, if you see what I mean - there'd have to be an extra level of indirection (which is what ArraySegment provides).

(I'm slightly surprised that ArraySegment doesn't do more wrapping, e.g. by implementing IList<T>, but there we go. It would be easy enough to create such a structure if you wanted to.)

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Agreed, didn't know that either. I'll keep my answer (should work as well), but this seems to be the "right way" (tm) – Benjamin Podszun Apr 08 '10 at 09:05
  • 1
    The memory layout of a jagged array makes it impractical to use unsafe constructs to get to their contents. If multiple dimensional arrays were used, it can be done and can be beneficiary in (rare) corner cases where the poor .NET performance on multi dim arrays is too slow for you. But you still cannot return a slice without copying and adding the new metadata. – Abel Apr 08 '10 at 09:08
  • @Abel: I understand that it is not jagged, just a long single-dimensional array. Think the ImageData bytes[] that you have to map to rows again to get something at a specified x, y. That's how I got him at least. – Benjamin Podszun Apr 08 '10 at 09:10
  • Hum, I have already created a wrapper with some kind of IArray : IEnumerable interface. Works nicely but means that I'll have to change/check all calls to GetDataReference in the code... even some code I have no access to.. – Wam Apr 08 '10 at 09:15
  • My remark was more-a-less meant in general, not to anyone in particular ;-). However, you (Benjamin) point at an interesting point: upon creation, a single-dimensional jagged array with each sub-array having the same size, has a memory layout usable with image processing or mathematics. However, only multi-dim arrays guarantee the layout, jagged arrays do not. – Abel Apr 08 '10 at 09:16
  • 2
    An ArraySegment class which could be used interchangeably with an array would be wonderful, but would require CLR support. ArraySegment and ReadonlyArraySegment structs which supported indexing operators, IEnumerable, and widening casts from array types would be nice too. Since ArraySegment doesn't support much of anything, I'm unclear what it's good for. – supercat Mar 14 '11 at 20:07
  • That would wonderfull. I have reasently created an ImmutableAlignedArray for easy interop with native code. It uses a Builder pattern and unfortunately unsafe for indexing and returning a pointer. I would to implement static ref TTo Unsafe.As(ref TFrom) and use it like As, float[]>(ref obj) but it may require CLR support – Jens Munk Jan 08 '23 at 04:05
1

Check the following question on SO, but don't use the accepted answer (you don't want to copy after all), but rather follow the other options of using an Enumerator for the slice/subpart of the original array.

Array slices in C#

Community
  • 1
  • 1
Benjamin Podszun
  • 9,679
  • 3
  • 34
  • 45