C#StructLayout.Explicit问题

时间:2009-07-25 19:05:28

标签: c# .net clr structlayout

我试图理解为什么下面的第二个例子没有问题,但第一个例子给了我下面的例外。在我看来,两个例子都应该基于描述给出例外。谁能开导我?

  

未处理的例外情况:   System.TypeLoadException:无法   从中加载类型'StructTest.OuterType'   程序集'StructTest,版本= 1.0.0.0,   Culture = neutral,PublicKeyToken = null'   因为它包含一个对象字段   错误对齐的偏移量0   或与非对象字段重叠。
  在StructTest.Program.Main(String []   args)按任意键继续。 。

示例1

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;

namespace StructTest
{
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    struct InnerType
    {
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 100)]
        char[] buffer;
    }

    [StructLayout(LayoutKind.Explicit)]
    struct OuterType
    {
        [FieldOffset(0)]
        int someValue;

        [FieldOffset(0)]
        InnerType someOtherValue;
    }

    class Program
    {
        static void Main(string[] args)
        {
            OuterType t = new OuterType();
            System.Console.WriteLine(t);
        }
    }
}

示例2

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;

namespace StructTest
{
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    struct InnerType
    {
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 100)]
        char[] buffer;
    }

    [StructLayout(LayoutKind.Explicit)]
    struct OuterType
    {
        [FieldOffset(4)]
        private int someValue;

        [FieldOffset(0)]
        InnerType someOtherValue;

    }

    class Program
    {
        static void Main(string[] args)
        {
            OuterType t = new OuterType();
            System.Console.WriteLine(t);
        }
    }
}

2 个答案:

答案 0 :(得分:11)

公共语言运行库包含一个验证程序,用于确保正在运行的代码(可验证的IL)不可能破坏托管环境中的内存。这可以防止您声明字段重叠的结构。基本上,您的struct包含两个数据成员。一个整数(4个字节)和本机整数(指针大小)。在32位CLR上,您可能正在运行代码,char[]将占用4个字节,因此如果您将整数小于4字节远离结构的开头,则您将拥有重叠字段。有趣的是,在64位运行时,两个代码片段都失败,因为指针大小为8个字节。

答案 1 :(得分:1)

我想我会用我用来创建联盟的解决方案做出回应 - 这是我的初衷。我使用了一个不安全的结构和一个固定数组,然后使用一个属性与固定数组进行交互。我相信这应该做我想要的。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;

namespace StructTest
{

    [StructLayout(LayoutKind.Explicit)]
    unsafe struct OuterType
    {
        private const int BUFFER_SIZE = 100;

        [FieldOffset(0)]
        private int transactionType;

        [FieldOffset(0)]
        private fixed byte writeBuffer[BUFFER_SIZE];

        public int TransactionType
        {
            get { return transactionType; }
            set { transactionType = value; }
        }

        public char[] WriteBuffer
        {
            set
            {
                char[] newBuffer = value;

                fixed (byte* b = writeBuffer)
                {
                    byte* bptr = b;
                    for (int i = 0; i < newBuffer.Length; i++)
                    {
                         *bptr++ = (byte) newBuffer[i];
                    }
                }
            }

            get
            {
                char[] newBuffer = new char[BUFFER_SIZE];

                fixed (byte* b = writeBuffer)
                {
                    byte* bptr = b;
                    for (int i = 0; i < newBuffer.Length; i++)
                    {
                        newBuffer[i] = (char) *bptr++;
                    }
                }

                return newBuffer;
            }
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            OuterType t = new OuterType();
            System.Console.WriteLine(t);
        }
    }
}