使用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
那么,如何在将报价信息转换为委托后保留报价信息?