如何在C#PCL中实现`FSharpValue.GetUnionFields`(Profile 259)

Ken*_*Ito 7 c# f# portable-class-library

我正在一个C#共享项目试图找到相当于的PCL(Profile 259)FSharpValue.GetUnionFields.

通过C#项目在对象浏览器中,我看到了

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

这似乎是我正在寻找的,但我无法(或不知道如何)从C#调用它.通过F#,如果我打开命名空间,我可以调用扩展名FSharpValue.GetUnionFields. FSharpValue.GetUnionFields不能从ac#PCL编译.我对F#没有经验,所以我可能只是缺少与F#相关的一些重要知识 - C#interop?

作为参考,这是我从F#pcl看到的.

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

val GetUnionFields : value:obj * unionType:System.Type * ?allowAccessToPrivateRepresentation:bool -> UnionCaseInfo * obj []
Run Code Online (Sandbox Code Playgroud)

Repro项目:https: //github.com/kennethito/StackOverflowReferences/tree/master/FSharpValue-GetUnionFields

Ree*_*sey 2

同样,这需要使用反射。由于它是 PCL,因此特别令人讨厌,因为运行时加载的 FSharp.Core 的实际版本才是重要的。

以下应该有效:

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 });
}
Run Code Online (Sandbox Code Playgroud)

它尝试直接在类型上查找方法(FSharp.Core 4.4 中是如何指定的),并回退到 PCL 结构(作为扩展方法)。

以下 C# 控制台应用程序显示它正在运行:

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();
}
Run Code Online (Sandbox Code Playgroud)