2010-01-24 6 views
12

Le .NET 4.0 Framework introduit des classes pour reading and writing memory mapped files. Les classes sont centrées autour des méthodes pour reading et writing structures. Ceux-ci ne sont pas rassemblés mais copiés depuis et vers le fichier sous la forme dans laquelle ils sont disposés dans la mémoire gérée.Taille des structures gérées

Disons que je veux écrire deux structures de manière séquentielle dans un fichier de mémoire mappée en utilisant ces méthodes:

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

Comment puis-je obtenir le nombre d'octets écrits dans (1) pour que je puisse écrire la valeur suivante de manière adjacente en 2)?

Remarque: Le nombre d'octets dans l'exemple est 3 (= 2 + 1), pas 5 (= 1 + 4) comme indiqué par Marshal.SizeOf.

Remarque 2: sizeof Impossible de déterminer la taille des paramètres de type générique.

Répondre

4

Il semble qu'il n'y ait aucun moyen documenté/public d'accéder à la fonction SizeOfType interne utilisé par la classe MemoryMappedViewAccessor, de sorte que le moyen le plus pratique d'obtenir la taille de ces structures serait d'utiliser la réflexion comme ceci:

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

C'est ce que je fais en ce moment. J'espérais une solution plus propre. S'appuyant sur des méthodes internes, non documentées n'est pas une très bonne idée IMO. – dtb

+0

D'après mon expérience, c'est souvent assez bon (au moins dans les applications serveur) et en outre, c'est généralement la seule façon de faire cette chose en particulier. –

2

Vous pouvez utiliser Emit pour accéder à la restriction du compilateur opcode et by-pass sizeof sur l'obtention 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

Questions connexes