2014-07-21 51 views
2

有没有一种方法来编组结构(可能存储在TypedReference)非托管内存没有实际装箱呢?结构的类型在运行时是未知的,所以我不能使用StructureToPtr(.NET 4.5.1)的通用重载。我可以得到一个MethodInfo的StructureToPtr重载,但似乎没有办法调用它通过通用引用或TypedReferenceMarshal.StructureToPtr没有装箱

编辑:通用StructureToPtr仍然结构的结构,所以试图调用它是没有用的。

+1

为什么你需要'StructureToPtr'的通用版本?编辑:即使通用版本只会调用非通用版本并导致一个框。 – leppie

+0

@leppie哦,我认为通用的一些做一些技巧,以避免拳击。它有什么目的,除了混淆? – IllidanS4

+0

也许有特殊处理,但没有我在文档中看到......不知道目的是什么...... – leppie

回答

2

我终于找到了答案,SafeBuffer类。它包含我想要的 - 使用TypedReference和通用参数的编组方法的结构。所以,这是非常简单的,然后进行包装:

public static unsafe class InteropTools 
{ 
    private static readonly Type SafeBufferType = typeof(SafeBuffer); 
    public delegate void PtrToStructureNativeDelegate(byte* ptr, TypedReference structure, uint sizeofT); 
    public delegate void StructureToPtrNativeDelegate(TypedReference structure, byte* ptr, uint sizeofT); 
    const BindingFlags flags = BindingFlags.NonPublic | BindingFlags.Static; 
    private static readonly MethodInfo PtrToStructureNativeMethod = SafeBufferType.GetMethod("PtrToStructureNative", flags); 
    private static readonly MethodInfo StructureToPtrNativeMethod = SafeBufferType.GetMethod("StructureToPtrNative", flags); 
    public static readonly PtrToStructureNativeDelegate PtrToStructureNative = (PtrToStructureNativeDelegate)Delegate.CreateDelegate(typeof(PtrToStructureNativeDelegate), PtrToStructureNativeMethod); 
    public static readonly StructureToPtrNativeDelegate StructureToPtrNative = (StructureToPtrNativeDelegate)Delegate.CreateDelegate(typeof(StructureToPtrNativeDelegate), StructureToPtrNativeMethod); 

    private static readonly Func<Type,bool,int> SizeOfHelper_f = (Func<Type,bool,int>)Delegate.CreateDelegate(typeof(Func<Type,bool,int>), typeof(Marshal).GetMethod("SizeOfHelper", flags)); 

    public static void StructureToPtrDirect(TypedReference structure, IntPtr ptr, int size) 
    { 
     StructureToPtrNative(structure, (byte*)ptr, unchecked((uint)size)); 
    } 

    public static void StructureToPtrDirect(TypedReference structure, IntPtr ptr) 
    { 
     StructureToPtrDirect(structure, ptr, SizeOf(__reftype(structure))); 
    } 

    public static void PtrToStructureDirect(IntPtr ptr, TypedReference structure, int size) 
    { 
     PtrToStructureNative((byte*)ptr, structure, unchecked((uint)size)); 
    } 

    public static void PtrToStructureDirect(IntPtr ptr, TypedReference structure) 
    { 
     PtrToStructureDirect(ptr, structure, SizeOf(__reftype(structure))); 
    } 

    public static void StructureToPtr<T>(ref T structure, IntPtr ptr) 
    { 
     StructureToPtrDirect(__makeref(structure), ptr); 
    } 

    public static void PtrToStructure<T>(IntPtr ptr, out T structure) 
    { 
     structure = default(T); 
     PtrToStructureDirect(ptr, __makeref(structure)); 
    } 

    public static T PtrToStructure<T>(IntPtr ptr) 
    { 
     T obj; 
     PtrToStructure(ptr, out obj); 
     return obj; 
    } 

    public static int SizeOf<T>(T structure) 
    { 
     return SizeOf<T>(); 
    } 

    public static int SizeOf<T>() 
    { 
     return SizeOf(typeof(T)); 
    } 

    public static int SizeOf(Type t) 
    { 
     return SizeOfHelper_f(t, true); 
    } 
} 

使用

Guid g = Guid.NewGuid(); 
int size = InteropTools.SizeOf(g); 
IntPtr mem = Marshal.AllocHGlobal(size); 
InteropTools.StructureToPtr(ref g, mem); 

Guid g2 = InteropTools.PtrToStructure<Guid>(mem); 

现在,它实际上有超过在Marshal类非通用对象回吐的方法有什么优势?看起来StructureToPtr需要的时间减少了大约80%,并且PtrToStructure可以减少将近95%的时间。此外,这些方法可以正确处理可空类型。

+1

你测试过x86和x64吗?在不安之间,拳击的表现特征会有所不同(如果你想包括这个,RyuJIT也是如此)。尽管我认为这确实没什么关系 - 如果编组是你想要完全消除的瓶颈(或者通过复制批量而不是单个值来减少开销)。 –

+0

@JeroenMostert不,但似乎我得到的结果是错误的。尽管在Release中运行,但所连接的调试器似乎仍然会影响性能。 – IllidanS4

+0

是的 - 事实上,Debug与Release通常对性能没有可衡量的影响,因为编译器对生成的IL进行的优化量实际上相当有限(它倾向于让抖动完成繁重的工作)。然而,在调试器下运行,完全使任何性能测试无效。 –