Как создать экземпляр структуры в куче в C#

Я работаю с C DLL, которая принимает параметры в виде вложенных остроконечных структур. Это упрощенная форма C# примерно так:

struct Point
{
    public double X;
    public double Y;
}

struct Rectangle
{
    public unsafe Point* LowLeft;
    public unsafe Point* TopRight;
}

Возникает вопрос, когда я хочу создать экземпляр структуры Rectangle, Как я могу создать экземпляр Point в куче, а затем назначить его адрес LowLeft а также TopRight поля?

Некоторые неправильные способы:

  • Использование ключевого слова C# new напрямую синтаксически неправильно:

    r.LowLeft = новая точка ();

  • Использование фиктивной переменной кажется неправильным, поскольку она размещается в куче и, таким образом, освобождается, когда мы покидаем область действия:

    var dummy = новая точка (); r.LowLeft = @dummy;

1 ответ

Решение

Исходя из того, что сказал М.Элми в комментариях, я попытался поместить структуру в неуправляемую память. К сожалению, я не знаю, как проверить, находится ли он в куче, стеке или чем-то еще, но теперь он определенно находится в неуправляемой памяти...

    static void Main(string[] args)
    {
        SuperStruct myStruct = new SuperStruct() { MyName = "Dan", MyNumber = 1 };
        SuperStruct myOtherStruct;

        IntPtr pointer = Marshal.AllocHGlobal(Marshal.SizeOf<SuperStruct>());

        Marshal.StructureToPtr(myStruct, pointer, false);

        myOtherStruct = Marshal.PtrToStructure<SuperStruct>(pointer);

        Console.WriteLine($"Name: {myOtherStruct.MyName}, Number: {myOtherStruct.MyNumber}.");
        Console.ReadLine();
    }
    struct SuperStruct
    {
        public int MyNumber;
        public string MyName;
    }

В целом, процесс выглядит следующим образом: 1) Настройте некоторую неуправляемую память, готовую для хранения данных, используя Marshal.AllocHGlobal, 2) Установите эту память, используя Marshal.StructureToPtr метод. 3) Получить эту структуру из неуправляемой памяти, используя Marshal.PtrToStructure<T> метод.

Также было отмечено (М.Элми в комментариях), что мы можем объявить типизированный указатель, если в определение структуры не включен управляемый тип, например:

        unsafe
        {
            SuperStruct* ptr = (SuperStruct*)pointer.ToPointer();
        }

В моем конкретном примере string поле запрещает вам использовать эту декларацию, но ее стоит поставить для последующего использования.

Другие вопросы по тегам