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...
void Foo<T>(T bar) where T : struct
– Buschipublic unsafe MyStruct* Ptr
declaration is compiled ok – Anthropoidwhere T : struct
, but it doesn't work. – Buschiref struct
that restricts creation of instance only in stack but not sure about such restriction in generic – Anthropoidref struct
scenario, but it is aref return
one :) – Ullman