Как создать экземпляр структуры в куче в 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
поле запрещает вам использовать эту декларацию, но ее стоит поставить для последующего использования.