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

时间:2016-03-29 19:20:00

标签: c# f# portable-class-library

我在C#共享项目中试图找到FSharpValue.GetUnionFields的PCL(Profile 259)等价物。

在对象浏览器中通过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);
    }
}

这似乎是我正在寻找的,但我无法(或不知道如何)从C#调用它。通过F#,如果我打开命名空间,我可以调用扩展名FSharpValue.GetUnionFieldsFSharpValue.GetUnionFields不能从c#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 []

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

1 个答案:

答案 0 :(得分: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 });
}

这试图直接在类型上找到方法(如何在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();
}