如何将递归结构编组为c sharp?

时间:2021-11-01 16:54:47

I have an unmanaged struct I'd like to marshal to c sharp that looks basically like this:

我有一个非管理的结构,我想整理到c sharp,看起来基本上是这样的:

struct MyStruct{  
    /* ... some stuff ... */
    int numChilds;  
    MyStruct *childs;
}

I believe that I have to write a custom marshaller but I'm not sure on how to proceed.

我相信我必须写一个自定义编组,但我不确定如何继续。

2 个解决方案

#1


I like to use a setup like this when I don't need to directly index children:

当我不需要直接索引孩子时,我喜欢使用这样的设置:

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;
            }
        }
    }
}

If you do need to directly index children, the easiest thing is creating a method GetChild (shown below). The harder way is creating a helper/wrapper class that implements IList<MyStruct>. An instance would be returned from the Children property, and its internal would work by calling the GetChild method. This is left as an exercise to the reader should he need it.

如果你确实需要直接索引子项,最简单的方法是创建一个方法GetChild(如下所示)。更难的方法是创建一个实现IList 的帮助器/包装器类。将从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;
}

#2


If you want just to pass it to some unmanaged function, you could just use unsafe code and stackalloc / fix an array to get a pointer to the array of objects.

如果你只想将它传递给一些非托管函数,你可以使用不安全的代码和stackalloc / fix一个数组来获取一个指向对象数组的指针。

        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);


        }

#1


I like to use a setup like this when I don't need to directly index children:

当我不需要直接索引孩子时,我喜欢使用这样的设置:

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;
            }
        }
    }
}

If you do need to directly index children, the easiest thing is creating a method GetChild (shown below). The harder way is creating a helper/wrapper class that implements IList<MyStruct>. An instance would be returned from the Children property, and its internal would work by calling the GetChild method. This is left as an exercise to the reader should he need it.

如果你确实需要直接索引子项,最简单的方法是创建一个方法GetChild(如下所示)。更难的方法是创建一个实现IList 的帮助器/包装器类。将从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;
}

#2


If you want just to pass it to some unmanaged function, you could just use unsafe code and stackalloc / fix an array to get a pointer to the array of objects.

如果你只想将它传递给一些非托管函数,你可以使用不安全的代码和stackalloc / fix一个数组来获取一个指向对象数组的指针。

        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);


        }