eaglet

本博专注于基于微软技术的搜索相关技术
随笔 - 189, 文章 - 0, 评论 - 3725, 阅读 - 147万
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

LayoutKind.Explicit 的平台兼容性问题

Posted on   eaglet  阅读(4527)  评论(5编辑  收藏  举报

昨天把我的 Hubble.net 项目在x64下测试发现有异常,但在32位操作系统下没有问题,抓狂!查了好几个小时最后发现居然是 LayoutKind.Explicit 的问题,网上搜索了半天,中英文的都看了,没找到为什么这个会造成.net 在不同平台上表现不一样,不管怎么样,我还是把这个问题写出来,大家看了以后可以避免犯同样的错误。

.net 号称是可以跨平台的,至少在 windows 平台下代码是可以相互移植的,代码的表现应该是一致的,这都是我想当然的结果,但昨天的这个问题打破了我美好的想象。问题是这样的,如果你的代码中有一个结构声明为 LayoutKind.Explicit ,且这个结构中有引用类型字段,那么在 64位操作系统(我只测试了windows2003 x64)下将存在反射问题。具体看下面代码:

    [StructLayout(LayoutKind.Explicit)]
    struct Struct1
    {
        [FieldOffset(0)]
        public int FileIndex;
 
        [FieldOffset(4)]
        public string Data;
    }

 

    [StructLayout(LayoutKind.Explicit)]
    struct Struct1
    {
        [FieldOffset(0)]
        public int FileIndex;
 
        [FieldOffset(4)]
        public int[] Data;
    }

    [StructLayout(LayoutKind.Explicit)]
    struct Struct1
    {
        [FieldOffset(0)]
        public int FileIndex;
 
        [FieldOffset(4)]
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 6)]
        public int[] Data;
    }

以上三个结构体是我用于测试的结构体,你的代码中只要有其中一个或类似的结构体定义,那么在 windows x64 下执行如下语句

            System.Reflection.Assembly asm = System.Reflection.Assembly.GetExecutingAssembly();
 
            foreach (Type type in asm.GetTypes())
            {
                Console.WriteLine(type);
            }

就会出现如下异常:

无法加载一个或多个请求的类型。有关更多信息,请检索 LoaderExceptions 属性。   在 System.Reflection.Module._GetTypesInternal(StackCrawlMark& stackMark)
   在 System.Reflection.Assembly.GetTypes()

 

但上述代码在 windows 32 位操作系统下(测试了 XP 和 windows 2003 32bit) 运行完全没有问题。我考虑会不会是编译时要指定平台为 x64 ,测试了一下,指定平台为 x64 后,在windows x64 下运行依然会产生上述异常。

但如果结构的定义为这样,在x64 下则不会出现异常。

    [StructLayout(LayoutKind.Explicit)]
    struct Struct1
    {
        [FieldOffset(0)]
        public int FileIndex;
        [FieldOffset(4)]
        public int Data;
    }

 

总结:

为了保证我们的.net 程序的平台兼容性,我们应尽量避免在采用 StructLayout(LayoutKind.Explicit) 属性申明的结果体中定义引用类型字段。至于为什么32bit 和 64bit 下结果不一样,我没有找到相关资料,如果哪位大侠知道,望不吝赐教,谢谢!

编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· .NET周刊【3月第1期 2025-03-02】
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· [AI/GPT/综述] AI Agent的设计模式综述
点击右上角即可分享
微信分享提示