Подтвердить что ты не робот

Размер управляемых структур

В платформе .NET 4.0 представлены классы для чтения и записи сопоставленных файлов памяти. Классы сосредоточены вокруг методов чтения и структуры писем. Они не сортируются, а копируются из файла и в файл в форме, в которой они располагаются в управляемой памяти.

Скажем, я хочу записать две структуры последовательно в файл с отображением памяти, используя следующие методы:

[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), а не 5 (= 1 + 4), как было возвращено маршалом .SizeOf.

Примечание 2: sizeof не может определить размер параметров типового типа.

4b9b3361

Ответ 1

Кажется, что нет документального/общедоступного способа доступа к внутренней функции 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

Вы можете использовать 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 sizeOfFunctuion = (Func<uint>)sizeOfMethod
    .CreateDelegate(typeof(Func<uint>));
int size = checked((int)sizeOfFunctuion());