vendredi 17 février 2023

Dotnet Reflection: Calling Invoke on MethodInfo With 'out' Parameter from F#

I retrieve a TryParse method for a given type like this:

open System.Reflection

let stringParser<'T> =
    typeof<'T>.GetMember("TryParse")
    |> Seq.cast<MethodBase>
    |> Seq.choose (fun m ->
        let parameterTypes =
            m.GetParameters()
            |> Array.map (fun p -> (p.ParameterType, p.Attributes))
        if parameterTypes =
            [| (typeof<string>, ParameterAttributes.None)
            ;  (typeof<'T>.MakeByRefType(), ParameterAttributes.Out) |] then Some m
        else None)
    |> Seq.exactlyOne

The question now is how to provide the second parameter when invoking the method, which contains the parse result as a reference. A mutable variable [1] leads to the 'type instantiation involves a byref type' compilation error, and a ref variable [2] leads to a type mismatch during runtime (given here, e.g., for uint16):

let fromString<'T> (s: string) =
    // [1]
    //let mutable parseResult = Unchecked.defaultof<'T>
    // Using '&parseResult' gives:
    // A type instantiation involves a byref type. This is not permitted by the rules of Common IL
    
    // [2]
    //let parseResult = ref (Unchecked.defaultof<'T>)
    // Using 'parseResult' produces a runtime exception:
    // System.ArgumentException: Object of type 'Microsoft.FSharp.Core.FSharpRef`1[System.UInt16]' cannot be converted to type 'System.UInt16&'.

    // How to declare parseResult to retrieve the method result?
    let potentialResult = stringParser<'T>.Invoke(null, [|s; parseResult|])
    match potentialResult with
    | :? bool as boolResult ->
        if boolResult then Some (parseResult)
        else None
    | _ -> None




Aucun commentaire:

Enregistrer un commentaire