C# 可闪电类型上的不可闪电错误
我有这个结构和代码:C# 可闪电类型上的不可闪电错误,c#,.net,struct,garbage-collection,marshalling,C#,.net,Struct,Garbage Collection,Marshalling,我有这个结构和代码: [StructLayout(LayoutKind.Sequential, Pack = 8)] private class xvid_image_t { [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] public int[] stride; // [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] // public IntPt
[StructLayout(LayoutKind.Sequential, Pack = 8)]
private class xvid_image_t
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public int[] stride;
// [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
// public IntPtr[] plane;
}
public int decore()
{
xvid_image_t myStruct = new xvid_image_t();
myStruct.stride = new int[4]; // can be commented out - same result
GCHandle.Alloc(myStruct, GCHandleType.Pinned);
// ...
}
当我尝试运行它时,我得到一个ArgumentException
说:
对象包含非基本数据或不可删除的数据
读后感
以下复杂类型也是可空袭类型:
- 可blittable类型的一维数组,例如整数数组。但是,包含可blittable类型的变量数组的类型本身不是可blittable的
- 仅包含可blittable类型的格式化值类型(以及作为格式化类型封送的类)。有关格式化值类型的详细信息,请参见值类型的默认封送处理
封送
,而且想理解这一点
所以我真正想知道的是:
[StructLayout(LayoutKind.Sequential)]
unsafe private struct xvid_image_t {
public fixed int stride[4];
}
请注意,必须将声明更改为结构类型。它现在是一种值类型,当您将其设置为局部变量时,不再需要使用GCHandle来固定该值。确保任何非托管代码(通常通过引用)都不会存储指向该结构的指针。那会爆炸得很厉害,完全无法诊断。不安全关键字在这里是合适的。如果它确实存储了指针,那么您确实需要对项目符号进行字节处理,并使用Marshal.AllocHGlobal()和Marshal.StructureToPtr()确保指针在非托管代码使用时保持有效。一个恼人的.NET限制是,它只能识别独立的
System.array
对象和System.String
,两者都是引用类型。用C#编写的代码可以使用固定的
数组(正如Hans Passant所指出的),但是.NET本身无法识别这种类型,并且使用固定数组的代码是不可验证的。此外,固定数组仅限于保存原语,不能被其他语言(如vb.net)访问
使用固定数组的两种替代方法是
- 将固定数组替换为总大小适当的字段组合(在大多数情况下使用N个变量,但可能将
替换为char[4]
,或将UInt32
替换为char[8]
)。如果数组不是太大,可以定义(通过剪切/粘贴或反射)一组静态方法,这些方法采用struct by ref并读取/写入适当的元素,然后创建一个委托数组来调用这些方法UInt64
- 用数组替换整个结构,然后将该数组的第一个元素作为
参数传递。这可能比在结构中使用ref
数组更“危险”,但这是我在vb.net中知道的唯一一种方法,它可以通过包含真正需要作为数组访问的内容的结构获得“pass by ref”语义fixed
虽然我可以理解值类型数组可能被认为是“令人困惑的”(特别是如果它们是自动装箱的),但在某些地方,它们可能是数组存储的语义正确的方法,无论是从允许COM互操作使用pass-by-ref语义的角度,还是从应该返回少量值的方法的角度来看。例如,在
System.Drawing2d
中,有一种方法将当前图形转换返回为float[6]
;除了通过实验,没有明确的方法可以知道在返回该数组后对其所做的更改是否会影响、可能会影响,或者保证不会影响其他任何内容。如果该方法返回值类型数组,则对返回数组的更改显然不会影响其他任何内容。尽管如此,无论值类型数组是否会成为框架的有用部分,事实仍然是,无论出于好的原因还是坏的原因,都不存在这样的东西。我从这个链接中获得了以下答案()
SItuLongEmailMsg msg = newSItuLongEmailMsg();
// set members
msg.text = new byte[2048];
// assign to msg.text
int msgSize = Marshal.SizeOf(msg);
IntPtr ptr = Marshal.AllocHGlobal(msgSize);
Marshal.StructureToPtr(msg, ptr, true);
byte[] dataOut = new byte[msgSize];
Marshal.Copy(ptr, dataOut, 0, msgSize);