代码之家  ›  专栏  ›  技术社区  ›  dtb

管理结构尺寸

  •  12
  • dtb  · 技术社区  · 15 年前

    .NET 4.0框架为 reading and writing memory mapped files . 这些类集中在 reading writing structures .这些文件不会被封送,而是以它们在托管内存中的布局形式从文件和复制到文件。

    假设我想使用以下方法将两个结构按顺序写入内存映射文件:

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    struct Foo
    {
        public char C;
        public bool B;
    }
    
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    struct Bar
    {
    }
    
    static void Write<T1, T2>(T1 item1, T2 item2)
        where T1 : struct
        where T2 : struct
    {
        using (MemoryMappedFile file = MemoryMappedFile.CreateNew(null, 32))
        using (MemoryMappedViewAccessor accessor = file.CreateViewAccessor())
        {
            accessor.Write<T1>(0L, ref item1);  //  <-- (1)
            accessor.Write<T2>(??, ref item2);  //  <-- (2)
        }
    }
    
    static void Main()
    {
        Foo foo = new Foo { C = 'α', B = true };
        Bar bar = new Bar { };
        Write(foo, bar);
    }
    

    如何获得(1)中写入的字节数,以便可以在(2)中相邻写入下一个值?

    注意:示例中的字节数是3(=2+1),而不是marshal.sizeof返回的5(=1+4)。

    注2: sizeof 无法确定泛型类型参数的大小。

    3 回复  |  直到 6 年前
        1
  •  4
  •   Pent Ploompuu    15 年前

    似乎没有文件/公开的方式来访问内部 SizeOfType 函数 MemoryMappedViewAccessor 类,因此获取这些结构大小的最实际方法是使用如下反射:

    static readonly Func<Type, uint> SizeOfType = (Func<Type, uint>)Delegate.CreateDelegate(typeof(Func<Type, uint>), typeof(Marshal).GetMethod("SizeOfType", BindingFlags.NonPublic | BindingFlags.Static));
    
    static void Write<T1, T2>(T1 item1, T2 item2)
        where T1 : struct
        where T2 : struct
    {
        using (MemoryMappedFile file = MemoryMappedFile.CreateNew(null, 32))
        using (MemoryMappedViewAccessor accessor = file.CreateViewAccessor())
        {
            accessor.Write(0, ref item1);
            accessor.Write(SizeOfType(typeof(T1)), ref item2);
        }
    }
    
        2
  •  2
  •   Glenn Slayden    6 年前

    可以使用emit访问sizeof操作码,并绕过编译器对获取sizeof(t)的限制:

    var sizeOfMethod = new DynamicMethod(
        "GetManagedSizeImpl"
    ,   typeof(uint)
    ,   null
    ,   true);
    var genSizeOf = sizeOfMethod.GetILGenerator();
    genSizeOf.Emit(OpCodes.Sizeof, typeof(T));
    genSizeOf.Emit(OpCodes.Ret);
    var sizeOfFunction = (Func<uint>)sizeOfMethod.CreateDelegate(typeof(Func<uint>));
    
    // ...
    int size = checked((int)sizeOfFunction());
    
        3
  •  0
  •   Glenn Slayden    6 年前

    1。 本页的一个答案建议使用内部函数 Marshal.SizeOfType ,但这只适用于不包含任何托管引用的结构。论 .NET 4.7 它抛出了一个 ArgumentException 传递引用时( class 类型,或 struct 包含嵌入引用的类型。

    2.第2条。 这里的另一个答案建议使用 IL sizeof 操作码。这对所有人都适用 结构 值类型——包括泛型和带有嵌入引用的值类型——但对于引用类型,它始终返回 IntPtr.Size ( 即。, 价值 4 8 ,与实际情况相反 布局尺寸 托管类的(实例)。这可能是你想要的,取决于你的情况。注意,通过将包含单个嵌入引用(handle)的结构的情况与单个引用(handle)本身合并,这种结果会很好地降低。

    调用 西泽 IL指令通过 System.Runtime.CompilerServices.Un­safe 包裹:

    int struct_layout_bytes = Unsafe.Sizeof<T>();
    

    三。 如果你 真正地 需要实际 布局尺寸 由于某种原因,托管类的(实例),那么您可能做了一些错误的事情,但是您可以通过以下方法获得它,这些方法只适用于引用类型,也就是说,当 typeof(T).IsValueType false .

    int class_layout_bytes = Marshal.ReadInt32(typeof(T).TypeHandle.Value, 4)
    

    第四章。 因此——还有前面的警告——得到 实例布局大小 对于 任何 引用或值类型——包括包含嵌入引用的类型——来自 Type 处理,结合方法2和3:

    int instance_layout_bytes = typeof(T).IsValueType ? 
                                    Unsafe.Sizeof<T>() : 
                                    Marshal.ReadInt32(typeof(T).TypeHandle.Value, 4);
    



    相关: Size of struct with generic type fields