0

I have a float array in C# that stores data. However, I need to cast the data to structures like Vector2, Vector3 etc. The structures are holding only floats, so there is no data type conversion in the matter of bytes, only in access.

Eg.:

struct Vector3 
{
  public float x;
  public float y;
  public float z;

  //plus some methods
}

I can copy the whole float array to the struct one manually by creating a new array, but that is kind of slow for big ones. I have tried to do conversion in unsafe code, but using generic is not working and creating special method for every struct I have is kind of "weird".

In C++ I have something like this:

float * arrayFloat = ....
Vector3 * arrayVector3 = reinterpret_cast<Vector3 *>(arrayFloat);

but that is not an option in C#...

Any ideas how to achieve this, or how to change the design?

Baum mit Augen
  • 49,044
  • 25
  • 144
  • 182
Martin Perry
  • 9,232
  • 8
  • 46
  • 114
  • 4
    *"In C++ I have something like this:"* No you don't, this violates strict aliasing. (Also padding, and whatever additional flavors of UB you may hit.) – Baum mit Augen Aug 01 '16 at 16:11
  • I have C++ struct with padding alignment and it should be "safe" under MSVC compiler – Martin Perry Aug 01 '16 at 17:22
  • Why not store the array in the `Vector2`, `Vector3`, ... class instead of three `double` values? Then you would only need to set the internal array of `Vector3` to the given array, and no copying would take place. – Kjara Aug 02 '16 at 10:43
  • If his structs held arrays, each one would require a heap allocation, and the array itself introduces quite a lot of memory overhead compared to this compact struct. – Timo Nov 19 '19 at 15:54

3 Answers3

4

you could add a constructor to your struct:

struct Vector3
{
   public float x;
   public float y;
   public float z;

   public Vector3(float[] vals)
   {
      if(vals.Length != 3)
         throw new ArgumentException();
      x = vals[0]; y = vals[1]; z = vals[2];
   }
}

...elsewhere

float[] myFloats = { 0.0f, 1.1f, 2.2f };
var myVec = new Vector3(myFloats);

if you're asking if there is something that lets you do this without any work, the answer is no. Any conversion from an array to a struct of your choosing has to be implemented by you, preferably in your struct.

Jakotheshadows
  • 1,485
  • 2
  • 13
  • 24
1

I believe this can work for your struct, using .NET Core 2.1's MemoryMarshal methods.

My answer here describes how. The essence is:

var vectors = MemoryMarshal.Cast<float, Vector3>(floatArray.AsSpan());
var firstVector = vectors[0];

This is C#'s equivalent of a reinterpret cast.

Timo
  • 7,992
  • 4
  • 49
  • 67
0

I'm new to C#, and i was struggling with the same problem, what i found useful is to use an enumerator which lazily converts every element on access:

IEnumerator<Vector3> Positions()
{
    for (int i = 0; i < _positions.Length / 3; ++i)
    {
        yield return new Vector3(_positions[3*i],
                                 _positions[3*i+1],
                                 _positions[3*i+2]);
    }
}

With this you don't need to copy the whole array and compiler most likely will not create new object of type Vector3 in memory instead it will use registers.

Yola
  • 18,496
  • 11
  • 65
  • 106