Search code examples
.netf#pinvokeunmanaged

why a generic struct parameterized by blittable type is not an unmanaged type?


I have one function foo, which takes an unmanaged type, then I create a generic struct, which require the type parameter to be unmanaged:

[<Struct>]
type Vector4<'T when 'T:unmanaged> =
    val x : 'T
    val y : 'T
    val z : 'T
    val w : 'T
    new (x, y, z, w) = { x = x; y = y; z = z; w = w }

let foo<'T when 'T:unmanaged> (o:'T) =
    printfn "%A" o
    printfn "%d" sizeof<'T>

let bar() =
    let o = Vector4<float32>(1.0f, 2.0f, 3.0f, 4.0f)
    foo o  // here has error

but I got compiling error:

Error 4 A generic construct requires that the type 'Vector4<float32>' is an unmanaged type

I checked the MSDN, it syas:

The provided type must be an unmanaged type. Unmanaged types are either certain primitive types (sbyte, byte, char, nativeint, unativeint, float32, float, int16, uint16, int32, uint32, int64, uint64, or decimal), enumeration types, nativeptr<_>, or a non-generic structure whose fields are all unmanaged types.

Why a generic struct which requires blittable type parameter is not an unmanaged type?


Solution

  • Generic types are not supported by Interop: [1], [2]

    The COM model does not support the concept of generic types. Consequently, generic types cannot be used directly for COM interop.

    Type alias is no help in this case unfortunately:

    [<Struct>]
    [<StructLayout(LayoutKind.Sequential)>]
    type Vector4<'T when 'T:unmanaged> =
        val x : 'T
        val y : 'T
        val z : 'T
        val w : 'T
        new (x, y, z, w) = { x = x; y = y; z = z; w = w }
    
    type Vector4float = Vector4<float32>
    
    let inline foo<'T when 'T:unmanaged> (o:'T) =
        printfn "%A" o
        printfn "%d" sizeof<'T>
    
    let bar() =
        let o = new Vector4float(1.0f, 2.0f, 3.0f, 4.0f)
        foo o //  A generic construct requires that the type 'Vector4float' is an unmanaged type