转换为委托后,报价将丢失

时间:2016-01-06 05:25:46

标签: reflection f# quotations

使用F#派生模式MethodWithReflectedDefinition,我们可以从MethodInfo获取引用对象。但是,如果我们将F#函数或成员方法转换为委托,即使函数或方法标记为[<ReflectedDefinition>],我们也无法获得引用。这是一个例子:

open System
open System.Reflection
open System.Runtime.CompilerServices
open Microsoft.FSharp.Quotations
open Microsoft.FSharp.Quotations.DerivedPatterns
open NUnit.Framework

let printQuotation (methodInfo:MethodInfo) =
    match methodInfo with
    | MethodWithReflectedDefinition expr -> printfn "%A" expr
    | _ -> printfn "Cannot get quotations."

let printQuotationFromDelegate (del:Func<int, int>) =
    printQuotation del.Method

[<ReflectedDefinition>]
let foo a = a + 1

type MyClass private () =

    [<ReflectedDefinition>]
    static member Foo(a:int) =
        a + 1

[<Test>]
let test() =
    let methodInfo = typeof<MyClass>.GetMethod("Foo", BindingFlags.Static ||| BindingFlags.Public)
    printQuotation methodInfo   // works

    // cannot get quotations
    printQuotationFromDelegate(Func<_,_> MyClass.Foo)

    // cannot get quotations
    printQuotationFromDelegate(Func<_,_> foo)

如果我检查程序集IL代码,我发现原因是,正常的foo值和MyType.Foo方法具有[ReflectedDefinition]属性:

.method public static 
    int32 Foo (
        int32 a
    ) cil managed 
{
    .custom instance void [FSharp.Core]Microsoft.FSharp.Core.ReflectedDefinitionAttribute::.ctor() = (
        01 00 00 00
    )
    // Method begins at RVA 0x2150
    // Code size 5 (0x5)
    .maxstack 8

    IL_0000: nop
    IL_0001: ldarg.0
    IL_0002: ldc.i4.1
    IL_0003: add
    IL_0004: ret
} // end of method MyClass::Foo

但转换后的委托不使用这些函数,它使用生成的方法,它是原始方法的副本。但不幸的是,这些生成的函数没有这样的ReflectedDefinition属性,我认为引用与这些生成的方法没有关联:

IL_0021: newobj instance void QuotationInDelegate/test@33::.ctor()
IL_0026: ldftn instance int32 QuotationInDelegate/test@33::Invoke(int32)
IL_002c: newobj instance void class [mscorlib]System.Func`2<int32, int32>::.ctor(object, native int)
IL_0031: call void QuotationInDelegate::printQuotationFromDelegate(class [mscorlib]System.Func`2<int32, int32>)

和生成的方法test@33:Invoke

.class nested assembly auto auto sealed specialname serializable beforefieldinit test@33
    extends [mscorlib]System.Object
{
    .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = (
        01 00 06 00 00 00 00 00
    )
    // Methods
    .method public specialname rtspecialname 
        instance void .ctor () cil managed 
    {
        // Method begins at RVA 0x2158
        // Code size 7 (0x7)
        .maxstack 8

        IL_0000: ldarg.0
        IL_0001: call instance void [mscorlib]System.Object::.ctor()
        IL_0006: ret
    } // end of method test@33::.ctor

    .method assembly hidebysig 
        instance int32 Invoke (
            int32 arg
        ) cil managed 
    {
        // Method begins at RVA 0x2160
        // Code size 8 (0x8)
        .maxstack 8

        IL_0000: nop
        IL_0001: ldarg.1
        IL_0002: call int32 QuotationInDelegate/MyClass::Foo(int32)
        IL_0007: ret
    } // end of method test@33::Invoke

} // end of class test@33

那么,如何在将报价信息转换为委托后保留报价信息?

0 个答案:

没有答案