I suggest you ...

Unmanaged generic type constraint + generic pointers

Add an "unmanaged"/"blittable" generic type constraint and use it to allow generic pointers and related features. Related post by Eric Lippert:

The end result would allow this sort of code:

unsafe void DoSomeStuff<T>() where T : unmanaged
T t = new T();
T* tPointer = &t;
T* aBunchOfT = stackalloc T[100];
var tSize = sizeof(T);
byte* aBunchOfBytes = stackalloc byte[tSize * 100];
T* aBunchOfCastedT = (T*)bunchOfBytes;

Performance critical generic data structures, particularly those using preallocated pools of memory, would be a good example use case for this.

Currently, a data structure using pointers to represent data would either need to be type specialized or its users would end up casting pointers. Type specialization hurts code reusability. Requiring external pointer casts is error prone and infects other code with unsafe code requirements. Generic pointers make it easy to modularize the reusable unsafe bits, allowing relatively-low-maintenance drop-in replacements for platforms that don't allow unsafe code.

Adding support for an unmanaged constraint and generic pointers would make reusable unsafe code cleaner and more reliable.

367 votes
Sign in
Sign in with: facebook google
Signed in as (Sign out)
You have left! (?) (thinking…)
Ross Nordby shared this idea  ·   ·  Flag idea as inappropriate…  ·  Admin →


Sign in
Sign in with: facebook google
Signed in as (Sign out)
  • Joe Amenta commented  ·   ·  Flag as inappropriate

    There's System.Runtime.CompilerServices.Unsafe and ref locals / ref returns in C# 7.0 now (the former requires the latter to work properly), which together enable basically the same stuff (just not anywhere nearly as safely as a language feature would be)... the equivalents to what's in the original suggestion would look approximately like:

    unsafe void DoSomeStuff<T>() where T : struct
    T t = default(T);
    ref T tPointer = ref t;

    // omitted aBunchOfT because it'd just look the same as...

    var tSize = Unsafe.SizeOf<T>();
    byte* aBunchOfBytes = stackalloc byte[tSize * 100];
    ref T aBunchOfCastedT = ref Unsafe.AsRef<T>(aBunchOfBytes);

    System.Runtime.CompilerServices.Unsafe then adds a bunch of helper methods that let you do basically all the same stuff with "aBunchOfCastedT" that you can do with a pointer. You can also get a void* from the managed pointer with Unsafe.AsPointer<T>(ref T value), just make sure that you can prove to yourself that your managed pointer isn't an interior pointer to something that the GC could relocate if it wanted to, since it obviously won't know to fix up the returned unmanaged pointer at the same time like it would with the managed interior pointer.

    It's definitely clunky since it's implemented in a library API instead of directly in the language, and it would still be nice to have an "unmanaged" type constraint so we could use this more safely if the generic type parameter could come in from shady folks, but it at least gives insane people like me the tools needed to implement the internals of certain things in a way that makes the (probably more sane) users happier about how much faster it is, all the same.

  • Anonymous commented  ·   ·  Flag as inappropriate

    I'd love to have this. This would help tremendously with C++ interrop and implementing many other low-level things.

  • Hongfaan LEI commented  ·   ·  Flag as inappropriate

    [System.Security.SecuritySafeCritical] versions of UnmanagedMemoryAccessor/SafeBuffer .Read/Write/ReadArray/WriteArray<T> can be done very easily (by .Net/CLR team) if C# has this feature.

  • Harry commented  ·   ·  Flag as inappropriate

    We would absolutely love to have this! Additionally, I think this would help the SIMD project and RyuJIT so the generic Vector<T> type can be constructed from a generic pointer T* also and not only from e.g. an IntPtr. So type safety would still apply.

Feedback and Knowledge Base