Как мне преобразовать рекурсивную структуру в c Sharp?
-
18-09-2019 - |
Вопрос
У меня есть неуправляемая структура, которую я хотел бы маршалировать в c Sharp, которая выглядит примерно так:
struct MyStruct{
/* ... some stuff ... */
int numChilds;
MyStruct *childs;
}
Я считаю, что мне нужно написать собственный маршаллер, но я не уверен, как действовать дальше.
Решение
Мне нравится использовать такую настройку, когда мне не нужно напрямую индексировать дочерние элементы:
struct MyStruct
{
/* ... some stuff ... */
int numChilds;
IntPtr childData;
public IEnumerable<MyStruct> Children
{
get
{
int elementSize = Marshal.SizeOf(typeof(MyStruct));
for (int i = 0; i < this.numChilds; i++)
{
IntPtr data = new IntPtr(this.childData.ToInt64() + elementSize * i);
MyStruct child = (MyStruct)Marshal.PtrToStructure(data, typeof(MyStruct));
yield return child;
}
}
}
}
Если вы делать нужно напрямую индексировать дочерние элементы, проще всего создать метод GetChild
(показано ниже).Более сложный способ — создать вспомогательный класс/класс-оболочку, реализующий IList<MyStruct>
.Экземпляр будет возвращен из Children
свойство, и его внутренняя часть будет работать, вызывая GetChild
метод.Это оставлено читателю в качестве упражнения, если оно ему понадобится.
public MyStruct GetChild(int index)
{
if (index < 0)
throw new ArgumentOutOfRangeException("index", "The index must be >= 0.");
if (index >= this.numChilds)
throw new ArgumentException("The index must be less than the number of children", "index");
int elementSize = Marshal.SizeOf(typeof(MyStruct));
IntPtr data = new IntPtr(childData.ToInt64() + elementSize * index);
MyStruct child = (MyStruct)Marshal.PtrToStructure(data, typeof(MyStruct));
return child;
}
Другие советы
Если вы хотите просто передать его какой-то неуправляемой функции, вы можете просто использовать небезопасный код и stackalloc/исправить массив, чтобы получить указатель на массив объектов.
unsafe struct Foo
{
public int value;
public int fooCount;
public Foo* foos;
}
[DllImport("dll_natv.dll")]
static extern void PrintFoos(Foo f);
public unsafe static void Main()
{
Foo* foos = stackalloc Foo[10];
for (int i = 0; i < 10; ++i)
foos[i].value = i;
Foo mainFoo = new Foo();
mainFoo.fooCount = 10;
mainFoo.value = 100;
mainFoo.foos = foos;
PrintFoos(mainFoo);
}