Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to achieve `FSharpValue.GetUnionFields` in a C# PCL (Profile 259)

I'm in a C# shared project trying to find the PCL (Profile 259) equivalent for FSharpValue.GetUnionFields.

In object browser via the C# project, I see

namespace Microsoft.FSharp.Reflection
{
    [AutoOpen]
    [CompilationMapping(SourceConstructFlags.Module)]
    public static class FSharpReflectionExtensions
    {
        public static Tuple<UnionCaseInfo, object[]> FSharpValue.GetUnionFields.Static(object value, Type unionType, [OptionalArgument] FSharpOption<bool> allowAccessToPrivateRepresentation);
    }
}

This appears to be what I'm looking for, but I'm unable (or don't know how) to call it from C#. Via F#, if I open the namespace, I can call the extension FSharpValue.GetUnionFields. FSharpValue.GetUnionFields does not compile from a c# PCL. I'm not experienced with F# so it could be I'm just lacking some important piece of knowledge related to F# - C# interop?

For reference, this is what I see from a F# pcl.

[<AutoOpen>]
module Microsoft.FSharp.Reflection.FSharpReflectionExtensions
open Microsoft.FSharp.Reflection

val GetUnionFields : value:obj * unionType:System.Type * ?allowAccessToPrivateRepresentation:bool -> UnionCaseInfo * obj []

Repro project here: https://github.com/kennethito/StackOverflowReferences/tree/master/FSharpValue-GetUnionFields

like image 386
Kenneth Ito Avatar asked Mar 29 '16 19:03

Kenneth Ito


1 Answers

Again, this requires using reflection. Since it's a PCL, it's particularly nasty, as the actual version of FSharp.Core loaded at runtime is the one that will matter.

The following should work:

public static Tuple<UnionCaseInfo, object[]> TestIt()
{
    var option = new FSharpOption<int>(123);

    MethodInfo method;
    try
    {
        // If "4.4.0.0" is loaded at runtime, get directly
        var t = typeof(FSharpValue);
        method = t.GetRuntimeMethods().First(mi => mi.Name == "GetUnionFields");
    }
    catch 
    {
        var t = typeof(FSharpReflectionExtensions);
        method = t.GetRuntimeMethods().First(mi => mi.Name == "FSharp.Value.GetUnionFields.Static");
    }
    return (Tuple<UnionCaseInfo, object[]>)method.Invoke(null, new object[] { option, option.GetType(), null });
}

This tries to find the method directly on the type (how it's specified in FSharp.Core 4.4), and falls back to the PCL structure (as an extension method).

The following C# console application shows it working:

static void Main(string[] args)
{
    Tuple<UnionCaseInfo, object[]> results = CsharpPortable.Test.TestIt();
    var uci = results.Item1;
    Console.WriteLine("{0}:", uci.Name);
    foreach (var pi in uci.GetFields())
    {
        Console.WriteLine("Property: {0}", pi.Name);
    }
    Console.ReadKey();
}
like image 165
Reed Copsey Avatar answered Nov 05 '22 07:11

Reed Copsey