【问题标题】:Marshal.SizeOf throws ArgumentException on enumsMarshal.SizeOf 在枚举上抛出 ArgumentException
【发布时间】:2013-07-26 15:08:42
【问题描述】:

考虑这段代码:

public enum MyEnum { V1, V2, V3 }

int size = Marshal.SizeOf(typeof(MyEnum));

它抛出异常:

“System.ArgumentException”类型的未处理异常发生在 测试控制台.exe

附加信息:不能输入“TestConsole.Program+MyEnum” 编组为非托管结构;没有有意义的大小或偏移量可以 被计算出来。

虽然这段代码没有抛出异常并且size包含4:

public enum MyEnum { V1, V2, V3 }

public struct MyStruct
{
    public MyEnum en;
}

int size = Marshal.SizeOf(typeof(MyStruct));

谁能解释为什么 .NET 框架无法确定第一个示例代码中的 enum 是 4 个字节?

更新

Marshal.Sizeof() 在这个通用方法中失败了:

public bool IoControlReadExact<T>(uint ioControlCode, out T output) where T : struct
{
    output = new T();

    int outBufferSize = Marshal.SizeOf(typeof(T));
    IntPtr outBuffer = Marshal.AllocHGlobal(outBufferSize);
    if (outBuffer == IntPtr.Zero)
        return false;
    try
    {
        uint bytesReturned;
        return IoControlRead(ioControlCode, outBuffer, (uint)outBufferSize, out bytesReturned) && ((uint)outBufferSize == bytesReturned);
    }
    finally
    {
        output = (T)Marshal.PtrToStructure(outBuffer, typeof(T));
        Marshal.FreeHGlobal(outBuffer);
    }
}

而且编译器并没有抱怨enum 不是struct

解决方案

我可以重构我的通用方法,使其适用于 structenum

// determine the correct output type:
Type outputType = typeof(T).IsEnum ? Enum.GetUnderlyingType(typeof(T)) : typeof(T);
//...
int outBufferSize = Marshal.SizeOf(outputType);
//...
output = (T)Marshal.PtrToStructure(outBuffer, outputType);

【问题讨论】:

  • this 没有解释原因,但给出了解决方法。
  • 相比之下,可以使用不安全代码创建指向MyEnum 的指针类型,即使用类型MyEnum*

标签: c# .net enums marshalling


【解决方案1】:

这似乎是由 ECMA-335 对枚举的要求之间的差异所施加的限制(ECMA-335 Partition II §14.3):

...它们应具有自动字段布局(第 10.1.2 节); ...

还有Marshal.SizeOf的期待:

当您没有结构时,您可以使用此方法。布局必须是顺序的或显式的。

基于此,您需要在调用Marshal.SizeOf 之前使用Enum.GetUnderlyingType

【讨论】:

  • 所有枚举都有自动布局,无论你是否明确给出底层类型。它是底层字节码元数据中的一个属性。
  • 请注意,以下代码是有效的(即使在unsafe 上下文之外)并给出预期值:const int s = sizeof(MyEnum);。所以 C# 编译器很乐意使用底层整数类型的“宽度”,并且表达式被认为是编译时常量。
  • 如果我们声明一个带有几个整数字段(比如)的struct,并用[StructLayout(LayoutKind.Auto)] 属性装饰结构,那么这个结构的行为就证实了上述答案与枚举类型完全一样。 “大小”。那就是 Marshal.SizeOf 抛出相同的异常,而 sizeof(...) 有效(但仅在 unsafe 上下文中允许,因为此“大小”不被视为编译时常量)。
【解决方案2】:

Marshal.SizeOf(t) 确实想要一个非托管结构,而枚举是一个托管结构。 .NET 可以计算出枚举的常量大小:

int size1 = sizeof(MyEnum);
Console.WriteLine("Enum: {0}", size1);
int size2 = Marshal.SizeOf(typeof(MyStruct));
Console.WriteLine("Struct: {0}", size2);

【讨论】:

  • 对于枚举的特殊情况,可能有 Enum.GetUnderlyingType 感兴趣的方法
  • 从 Wouter Huysentruit 复制代码并读取异常 'Type 'MyEnum' cannot be marshaled as an unmanaged structure;无法计算出有意义的大小或偏移量。'
  • Enum 不是结构,就像 System.Int32 不是结构一样,即使它是这样声明的。只有当值类型值是 boxed 时,这样的声明才相关。
猜你喜欢
  • 2012-08-10
  • 2018-11-11
  • 1970-01-01
  • 1970-01-01
  • 2017-09-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-07
相关资源
最近更新 更多