2010-01-24 23 views
12

.NET 4.0 Framework wprowadza klasy dla reading and writing memory mapped files. Klasy są skupione wokół metod dla reading i writing structures. Nie są one sortowane, ale kopiowane z pliku i do pliku w formie, w której są układane w zarządzanej pamięci.Wielkość zarządzanych struktur

Powiedzmy chcę napisać dwie struktury kolejno do pliku pamięci odwzorowany za pomocą następujących metod:

[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); 
} 

Jak uzyskać liczbę bajtów zapisanych w (1), więc mogę napisać kolejną wartość przylegle w 2)?

Uwaga: Liczba bajtów w przykładzie to 3 (= 2 + 1), a nie 5 (= 1 + 4) zwracane przez użytkownika Marshal.SizeOf.

Uwaga 2: sizeof nie może określić rozmiaru ogólnych parametrów typu.

Odpowiedz

4

Wydaje się, że ma udokumentowane/sposób publiczny dostęp do wewnętrznego SizeOfType funkcję używaną przez klasę MemoryMappedViewAccessor, więc najbardziej praktycznym sposobem na uzyskanie rozmiaru tych struktur byłoby użyć refleksji tak:

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

to, co robię w tej chwili. Miałem nadzieję na czystsze rozwiązanie. Opieranie się na wewnętrznych, nieudokumentowanych metodach nie jest dobrym pomysłem IMO. – dtb

+0

Z mojego doświadczenia wynika, że ​​często jest to wystarczająco dobre (przynajmniej w aplikacjach serwerowych), a ponadto zazwyczaj jest to jedyny sposób na zrobienie tego właśnie. –

2

można użyć wystawi na ograniczenie dostępu sizeof oPCODE i bypass kompilator na uzyskanie 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()); 
+2

Большое спасибо за ответ, извините за беспокойство. – Other