Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/294.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 可闪电类型上的不可闪电错误_C#_.net_Struct_Garbage Collection_Marshalling - Fatal编程技术网

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类型的格式化值类型(以及作为格式化类型封送的类)。有关格式化值类型的详细信息,请参见值类型的默认封送处理

我不明白我做错了什么。 我不仅想使用
封送
,而且想理解这一点

所以我真正想知道的是:

  • 为什么?
  • 我如何解决这个问题
  • 您提供的解决方案是否也适用于结构中的注释行
  • 我使用的是.NET4.5,但也需要一个.NET2.0的解决方案

    对象包含非基本数据或不可删除的数据

    这是您收到的异常消息。你关注的是信息中“不可飞航”的部分,但这不是问题所在。问题在于“非原始”部分。数组是非基本数据类型

    CLR试图让你远离这里的麻烦。可以固定对象,但仍然存在问题,阵列将不会固定。当一个对象的字段也需要固定时,它就不会被真正固定

    而且UnmanagedType.ByValArray还有一个更大的问题,需要进行结构转换。换句话说,您需要的布局与托管类对象的布局完全不同。只有pinvoke封送员才能进行此转换

    通过使用固定大小的缓冲区,使用固定关键字,无需使用pinvoke marshaller即可获得所需内容。这需要使用不安全关键字。让它看起来像这样:

        [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]
      替换为
      UInt64
      )。如果数组不是太大,可以定义(通过剪切/粘贴或反射)一组静态方法,这些方法采用struct by ref并读取/写入适当的元素,然后创建一个委托数组来调用这些方法

    • 用数组替换整个结构,然后将该数组的第一个元素作为
      ref
      参数传递。这可能比在结构中使用
      fixed
      数组更“危险”,但这是我在vb.net中知道的唯一一种方法,它可以通过包含真正需要作为数组访问的内容的结构获得“pass by ref”语义


    虽然我可以理解值类型数组可能被认为是“令人困惑的”(特别是如果它们是自动装箱的),但在某些地方,它们可能是数组存储的语义正确的方法,无论是从允许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);