Return unsafe pointer to type parameter

放肆的年华 提交于 2020-01-29 03:45:07

问题


I am trying to define a property that returns a pointer to a generic type argument like so:

public class MemWrapper<T> where T: struct
{
    readonly IntPtr pointerToUnmanagedHeapMem;

    // ... do some memory management also ...

    public unsafe T* Ptr
    {
        get {return (T*)(pointerToUnmanagedHeapMem);}
    }
}

The compiler complains that it is not possible to declare a pointer to the managed type T or get its address or size (CS0208). The curious thing is, if I manually replace the generic type parameter by a concrete struct, that is

public class MyStructMemWrapper
{
    readonly IntPtr pointerToUnmanagedHeapMem;

    // ... do some memory management also ...

    public unsafe MyStruct* Ptr
    {
        get {return (MyStruct*)(pointerToUnmanagedHeapMem);}
    }
}

everything compiles fine. But then I would have to create a specialized version of the wrapper for every struct I use. So why does the generic even care about what kind of unsafe pointer it is casting?

Background information: I am using a native dll which in turn calls my c# callback function and passes to it my most general user data structure as a pointer (to be more precise: disguised as an IntPtr). In order to be able to pass a GC-stable pointer at all I am allocating my user data structure on the unmanaged heap. Consequently I have to take care that the memory is set free again in the end.

Since this is of course all at the limits of what a devoted c# programmer can suffer, I am creating a wrapper class (around that heap allocation and usage of the pointers to struct) which separates me as much as possible from the ugly stuff. In order to assign values to the structure on the unmanaged heap as easily as possible I want to define the above property.

public struct MyStruct {public double x;}

// ...

MemWrapper<MyStruct> m = new MemWrapper<MyStruct>();

unsafe
{
    // ideally I would like to get rid of the whole 
    // bloody unsafe block and directly write m.x = 1.0
    m.Ptr->x = 1.0;
}

Of course the unsafe property would only be a minor convenience improvement (over returning the unspecific IntPtr directly and casting it to an unsafe pointer from the outside), and so it is probably not worth it at all cost. But now as the problem is on the table I would like to understand it.

Edit: it seems like the problem is, that I assume the struct to be composed of value types only, which allows me to determine its size and so allocate it on the heap. In the specialized version the composition of the struct is indeed known to the compiler.

However in the generic version the struct could also be composed of reference (i.e. managed) types, although I would never do that due to the aforementioned reasons. Unless I am able to write a generic constraint like "where T: struct is composed of value types" I seem to be out of luck...


回答1:


Generics and pointers don't work well together, but this is actually a perfect fit for "ref return":

public class MemWrapper<T> where T : struct
{
    readonly IntPtr pointerToUnmanagedHeapMem;

    // ... do some memory management also ...

    public unsafe ref T Ptr
    {
        get { return ref Unsafe.AsRef<T>(pointerToUnmanagedHeapMem.ToPointer()); }
    }
}

Alternative Ptr syntax:

public unsafe ref T Ptr => ref Unsafe.AsRef<T>(pointerToUnmanagedHeapMem.ToPointer());

Note that this requires recent versions of Unsafe; here I'm using:

<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="4.4.0" />

Note that you now don't need unsafe in the consuming code - just the one property that touches pointerToUnmanagedHeapMem.

Consuming code:

var wrapper = ... // some MemWrapper<T>
ref Foo foo = ref wrapper.Ptr;
Console.WriteLine(foo.SomeProperty); // not foo->SomeProperty
SomeInnerMethod(ref foo); // pass down to other ref Foo methods

no unmanaged pointers; the code is now perfectly "safe" outside of .Ptr.

Note: if you need to talk about multiple consecutive items: Span<T>/Memory<T> are your friends.



来源:https://stackoverflow.com/questions/49345339/return-unsafe-pointer-to-type-parameter

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!