【问题标题】:ICustomMarshaler variable length arrayICustomMarshaler 可变长度数组
【发布时间】:2011-10-21 21:15:54
【问题描述】:

我知道可以使用数组中的索引来指定编组 C 数组的数组长度。不过,我想做点不一样的。

我希望大小为前缀 Int16。如果我将它作为数组的条目,我将无法控制计数说明符的封送大小。

所以,简而言之,我如何编写一个自定义编组器,将 Int16 作为计数作为前缀。

请注意,我必须对数据进行序列化,所以不允许使用 IntPtrs。

我被难住的部分是如何实现 GetNativeDataSize。那时我没有 IntPtr 或托管对象,那么我将如何编组 Int16 来获得计数。

例如。

[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
class Something
{
    [MarshalAs(UnmanagedType.CustomMarshaler ... ]
    public ArrayItem[];
}

还有其他类

[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
class ArrayItem
{
    public int Item;
}

在 Native 端,这会显示为

struct
{
    short count;
    int[] Item;
}

但是由于托管端的每个可变长度数组都会执行此操作,因此我想要一个自定义编组器来为我附加计数。

问题是

  • 我不知道 GetNativeDataSize 应该做什么,也不知道它是如何工作的,因为我没有对本机数据的任何引用。
  • 我不能依赖 LPArray,因为计数必须是 Int16
  • 数组项是否正确编组,或者数组自定义编组器是否隐藏项编组器,或者我将不得不实现一些通用编组器(如果可能的话)。

【问题讨论】:

标签: c# marshalling


【解决方案1】:

我要说...自定义封送器感觉有点矫枉过正。如果您真的想使用自定义封送器执行此操作,您将不得不使用 unsafe 块/方法和指针数学来写入数据。

为什么没有一个类似于你的原生结构的类,并在编组时将你的数组包装在其中?确实,无论如何您都在尝试传递结构;自定义封送拆收器的唯一原因是从数组中神奇地生成该结构。最好避免使用魔法,IMO,同时让默认的封送处理程序完成繁重的工作。

【讨论】:

  • 问题是,使用可变长度数组,您还没有解决反序列化问题。所以现在我们回到第一方,仍然没有答案。
  • @Xaade:对于大多数阵列,无论如何你都会遇到一些重大问题。自定义封送处理程序的 GetNativeDataSize 方法没有获得指向数据的指针(因为它还没有被复制,因为运行时需要知道要复制多少),所以你能做的最好的就是指定最大值(32768*sizeof(int),记住大多数 C 编译器会插入填充以双字对齐整数)。如果数组靠近堆栈底部或堆顶部,这很容易中断。您需要与本机代码进行一些合作才能获得大小。
  • 我刚刚编写了一个完整的自定义序列化程序类。这个东西处理从动态数组到字符串等的所有事情。编组只是没有很好地满足我的目的。
  • @cHao, GetNativeDataSize 只是为了帮助 GC 知道你在做多少内存“压力”。您可以从 MS 安全地返回 -1,就像在此示例中一样:support.microsoft.com/kb/307713
猜你喜欢
  • 2020-11-20
  • 2014-07-27
  • 1970-01-01
  • 2011-01-20
  • 2012-12-17
  • 2016-04-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多