Better solution to allocate buffer for array within structure for C#?

Viewed 174

I'm a beginner level in C# and have a question.

In C programming, I understand I could reference the following code to read/write the array data in structure member, while structure has lots of member, like A[128], B[128], ...,M[64], N[128], ...,X[32], Y[32], Z[128], ..., the main code has no need to add allocate buffer code to access the buffer array, it's clear and simple.

struct myStructB{
    int cnt;
    float AA[32];
    float BB[32];
    float CC[128];
};

struct myStructA{
    int cnt;
    int A[128];
    int B[128];
    int C[32];
    ...
    int M[64];
    int N[128];
    ...
    int Z[128];
    myStructB strctB;
};

myStructA testStruct;
int _tmain(int argc, _TCHAR* argv[])
{
    testStruct.A[0] = 123;
    testStruct.B[0] = 456;
    testStruct.C[0] = 789;
    testStruct.strctB.AA[0] = 321;
    testStruct.strctB.BB[0] = 654;
    testStruct.strctB.CC[0] = 987;
    
    int sss = testStruct.strctB.AA[0];
    return 0;
}

In C#, I guess I should allocate buffer for array within structure as the following, if the structure has lots of array element, the code is not simple, must allocation all array members. I don't think it's a good idea..... Is there a better solution to improve this code? I wanna pass this struct object to C++ DLL. Thanks :)

[StructLayout(LayoutKind.Sequential)]
struct myStructB{
    public int cnt;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
    public int[] AA;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
    public int[] BB;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
    public int[] CC;
}

[StructLayout(LayoutKind.Sequential)]
struct myStructA{
    public int cnt;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
    public int[] A;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
    public int[] B;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
    public int[] C;
    ...
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
    public int[] M;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
    public int[] N;
    ...
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
    public int [] Z;
    ...
    public myStructB strctB; 
}

myStructA testStruct = new myStructA();
testStruct.A = new int[128];
testStruct.B = new int[128];
testStruct.C = new int[32];
...
testStruct.M = new int[64];
testStruct.N = new int[128];
...
testStruct.Z = new int[128];

testStruct.strctB.AA = new int[128];
testStruct.strctB.BB = new int[128];
testStruct.strctB.CC = new int[32];

testStruct.A[0] = 123;
testStruct.B[0] = 456;
testStruct.C[0] = 789;
testStruct.strctB.AA[0] = 321;
testStruct.strctB.BB[0] = 654;
testStruct.strctB.CC[0] = 987;
1 Answers

If you want to embed the whole array into the struct itself you can use fixed buffers:

public unsafe ref struct MyStructB
{
    public const int Cnt = 128;
    public fixed float AA[Cnt/4];
    public fixed float BB[Cnt/4];
    public fixed float CC[Cnt];
}

public unsafe ref struct myStructA
{
    public const int Cnt = 32;
    public fixed float AA[Cnt];
    public MyStructB structB;
};

ref means that MyStruct can't be boxed. It enforces that MyStruct is always allocated on the stack. This is not a must-have, but you can think about it.

Usage:

unsafe
{
    var x = new MyStructB();
    // Accessing the first element AFTER AA, so you see why this is unsafe ;)
    x.AA[32] = 100;
    Console.WriteLine(x.BB[0]);  // 100; welcome to good old C
}

In your project settings you have to allow unsafe blocks (csproj file):

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net5.0</TargetFramework>
    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
  </PropertyGroup>

Therefore I would create an own wrapper library to minimize the scope of allowing unsafe execution.

Related