Size of managed structures

前端 未结 3 728
野趣味
野趣味 2020-12-09 05:47

The .NET 4.0 Framework introduces classes for reading and writing memory mapped files. The classes are centred around methods for reading and writing structures. These are n

相关标签:
3条回答
  • 2020-12-09 06:05

    1. One answer on this page proposes using the internal function Marshal.SizeOfType, but this only works for structs which do not contain any managed references. On .NET 4.7 it throws an ArgumentException when passed a reference (class) type, or a struct type which contains embedded references.

    2. Another answer here suggests using the IL sizeof opcode. This works correctly for all struct value types--including generics and those with embedded references--but for reference types it always returns IntPtr.Size (i.e., the value 4 or 8), as opposed to the actual layout size of (an instance of) the managed class. This may be what you want, depending on your situation. Note that this sort of result gracefully degrades by conflating the case of a struct containing a single embedded reference (handle) with a single reference (handle) itself.

    A simpler way to invoke the sizeof IL instruction is via the System.Runtime.CompilerServices.Un­safe package:

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

    3. If you truly need the actual layout size of (an instance of) a managed class for some reason, then you're probably doing something wrong, but you can obtain it via the following, which only works for reference types, that is, when typeof(T).IsValueType is false.

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

    4. Therefore--and still with the preceding caveat--to get the instance layout size for any reference- or value-type--including those containing embedded references--from its Type handle, combine methods #2 and #3:

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



    related: Size of struct with generic type fields

    0 讨论(0)
  • 2020-12-09 06:17

    You can use Emit to access the Sizeof opcode and bypass compiler's restriction on getting 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());
    
    0 讨论(0)
  • 2020-12-09 06:23

    It seems there is no documented/public way to access the internal SizeOfType function used by the MemoryMappedViewAccessor class, so the most practical way of getting the size of those structures would be to use reflection like this:

    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);
        }
    }
    
    0 讨论(0)
提交回复
热议问题