如果我有这样的事情:
type public ServiceActionType =
| ServiceRequest
| ServiceResponse
| ServiceEventInvocation
| ServiceEventSubscriptionRequest
| ServiceMetadataRequest
然后如何将其中一项添加到堆栈中,如下所示:
IlGen.Emit(OpCodes.???, ???)
如果我有这样的事情:
type public ServiceActionType =
| ServiceRequest
| ServiceResponse
| ServiceEventInvocation
| ServiceEventSubscriptionRequest
| ServiceMetadataRequest
然后如何将其中一项添加到堆栈中,如下所示:
IlGen.Emit(OpCodes.???, ???)
现有答案很好,但请注意,Microsoft.FSharp.Reflection
命名空间有一些帮助程序,可以轻松获取您关心的成员:
open Reflection
let cases = FSharpType.GetUnionCases(typeof<ServiceActionType>)
let serviceRequestMethod = FSharpValue.PreComputeUnionConstructorInfo(cases.[0])
结果是一样的,typeof<ServiceActionType>.GetMethod("get_ServiceRequest")
但你不必担心知道编译的形式,这可能会根据联合案例是否有字段而有所不同。
通常,可区分联合被编译为类层次结构(这意味着可区分联合的每个案例都有一个新的子类)。但是,在您的情况下,情况更简单,因为没有一个案例带有任何值。
如果您查看编译后的代码,您会看到生成的 .NET 表示形式为您提供如下内容:
class ServiceActionType {
public static ServiceActionType ServiceRequest { get; }
public static ServiceActionType ServiceResponse { get; }
public static ServiceActionType ServiceEventInvocation { get; }
// etc. for all the other cases
}
这意味着,如果您想构造可区分联合的值之一,您只需要发出对代表您想要的情况的(静态)属性的 getter 方法的调用。
如果您有一个带参数的案例,例如ServiceRequest of RequestInfo
,那么生成的类将包含一个NewServiceRequest
方法,该方法将采用必要的参数:
public static ServiceActionType NewServiceRequest(RequestInfo info);
也就是说,我不完全确定您为什么要这样做,因此发出代码可能不是最好的方法。您还可以考虑使用 F# 引用 - 它可以编译为动态方法 - 并且创建一个表示 DU 案例构造的引用非常容易使用Expr.NewUnionCase
。
让我们举个ServiceActionType.ServiceRequest
例子。
我将以下内容放在 LINQPad(F# 程序模式)中以获取 IL(但您可以将ildasm.exe
其用于相同目的):
type public ServiceActionType =
| ServiceRequest
| ServiceResponse
| ServiceEventInvocation
| ServiceEventSubscriptionRequest
| ServiceMetadataRequest
ServiceRequest.Dump()
它给了我:
IL_0001: call Query_qdoovg+ServiceActionType.get_ServiceRequest
IL_0006: call LINQPad.FSharpExtensions.Extensions.Dump
Dump:
IL_0000: nop
IL_0001: ldarg.0
IL_0002: box 03 00 00 1B
IL_0007: call LINQPad.FSharpExtensions.Extensions.Dump
IL_000C: ret
ServiceActionType.get_ServiceMetadataRequest:
IL_0000: ldsfld Query_qdoovg+ServiceActionType._unique_ServiceMetadataRequest
IL_0005: ret
ServiceActionType.get_IsServiceMetadataRequest:
IL_0000: ldarg.0
IL_0001: call Query_qdoovg+ServiceActionType.get_Tag
IL_0006: ldc.i4.4
IL_0007: ceq
IL_0009: ret
ServiceActionType.get_ServiceEventSubscriptionRequest:
IL_0000: ldsfld Query_qdoovg+ServiceActionType._unique_ServiceEventSubscriptionRequest
IL_0005: ret
ServiceActionType.get_IsServiceEventSubscriptionRequest:
IL_0000: ldarg.0
IL_0001: call Query_qdoovg+ServiceActionType.get_Tag
IL_0006: ldc.i4.3
IL_0007: ceq
IL_0009: ret
ServiceActionType.get_ServiceEventInvocation:
IL_0000: ldsfld Query_qdoovg+ServiceActionType._unique_ServiceEventInvocation
IL_0005: ret
ServiceActionType.get_IsServiceEventInvocation:
IL_0000: ldarg.0
IL_0001: call Query_qdoovg+ServiceActionType.get_Tag
IL_0006: ldc.i4.2
IL_0007: ceq
IL_0009: ret
ServiceActionType.get_ServiceResponse:
IL_0000: ldsfld Query_qdoovg+ServiceActionType._unique_ServiceResponse
IL_0005: ret
ServiceActionType.get_IsServiceResponse:
IL_0000: ldarg.0
IL_0001: call Query_qdoovg+ServiceActionType.get_Tag
IL_0006: ldc.i4.1
IL_0007: ceq
IL_0009: ret
ServiceActionType.get_ServiceRequest:
IL_0000: ldsfld Query_qdoovg+ServiceActionType._unique_ServiceRequest
IL_0005: ret
ServiceActionType.get_IsServiceRequest:
IL_0000: ldarg.0
IL_0001: call Query_qdoovg+ServiceActionType.get_Tag
IL_0006: ldc.i4.0
IL_0007: ceq
IL_0009: ret
ServiceActionType.get_Tag:
IL_0000: ldarg.0
IL_0001: ldfld Query_qdoovg+ServiceActionType._tag
IL_0006: ret
ServiceActionType.__DebugDisplay:
IL_0000: ldstr "%+0.8A"
IL_0005: newobj Microsoft.FSharp.Core.PrintfFormat<Microsoft.FSharp.Core.FSharpFunc<Query_qdoovg+ServiceActionType,System.String>,Microsoft.FSharp.Core.Unit,System.String,System.String,System.String>..ctor
IL_000A: call Microsoft.FSharp.Core.ExtraTopLevelOperators.PrintFormatToString
IL_000F: ldarg.0
IL_0010: callvirt Microsoft.FSharp.Core.FSharpFunc<Query_qdoovg+ServiceActionType,System.String>.Invoke
IL_0015: ret
ServiceActionType.CompareTo:
IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldnull
IL_0003: cgt.un
IL_0005: brfalse.s IL_0027
IL_0007: ldarg.1
IL_0008: ldnull
IL_0009: cgt.un
IL_000B: brfalse.s IL_0025
IL_000D: ldarg.0
IL_000E: ldfld Query_qdoovg+ServiceActionType._tag
IL_0013: stloc.0
IL_0014: ldarg.1
IL_0015: ldfld Query_qdoovg+ServiceActionType._tag
IL_001A: stloc.1
IL_001B: ldloc.0
IL_001C: ldloc.1
IL_001D: bne.un.s IL_0021
IL_001F: ldc.i4.0
IL_0020: ret
IL_0021: ldloc.0
IL_0022: ldloc.1
IL_0023: sub
IL_0024: ret
IL_0025: ldc.i4.1
IL_0026: ret
IL_0027: ldarg.1
IL_0028: ldnull
IL_0029: cgt.un
IL_002B: brfalse.s IL_002F
IL_002D: ldc.i4.m1
IL_002E: ret
IL_002F: ldc.i4.0
IL_0030: ret
ServiceActionType.CompareTo:
IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldarg.1
IL_0003: unbox.any Query_qdoovg.ServiceActionType
IL_0008: call Query_qdoovg+ServiceActionType.CompareTo
IL_000D: ret
ServiceActionType.CompareTo:
IL_0000: nop
IL_0001: ldarg.1
IL_0002: unbox.any Query_qdoovg.ServiceActionType
IL_0007: stloc.0
IL_0008: ldarg.0
IL_0009: ldnull
IL_000A: cgt.un
IL_000C: brfalse.s IL_0033
IL_000E: ldarg.1
IL_000F: unbox.any Query_qdoovg.ServiceActionType
IL_0014: ldnull
IL_0015: cgt.un
IL_0017: brfalse.s IL_0031
IL_0019: ldarg.0
IL_001A: ldfld Query_qdoovg+ServiceActionType._tag
IL_001F: stloc.1
IL_0020: ldloc.0
IL_0021: ldfld Query_qdoovg+ServiceActionType._tag
IL_0026: stloc.2
IL_0027: ldloc.1
IL_0028: ldloc.2
IL_0029: bne.un.s IL_002D
IL_002B: ldc.i4.0
IL_002C: ret
IL_002D: ldloc.1
IL_002E: ldloc.2
IL_002F: sub
IL_0030: ret
IL_0031: ldc.i4.1
IL_0032: ret
IL_0033: ldarg.1
IL_0034: unbox.any Query_qdoovg.ServiceActionType
IL_0039: ldnull
IL_003A: cgt.un
IL_003C: brfalse.s IL_0040
IL_003E: ldc.i4.m1
IL_003F: ret
IL_0040: ldc.i4.0
IL_0041: ret
ServiceActionType.GetHashCode:
IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldnull
IL_0003: cgt.un
IL_0005: brfalse.s IL_003C
IL_0007: ldc.i4.0
IL_0008: stloc.0
IL_0009: ldarg.0
IL_000A: call Query_qdoovg+ServiceActionType.get_Tag
IL_000F: switch (IL_0028, IL_002C, IL_0030, IL_0034, IL_0038)
IL_0028: ldc.i4.0
IL_0029: stloc.0
IL_002A: ldloc.0
IL_002B: ret
IL_002C: ldc.i4.1
IL_002D: stloc.0
IL_002E: ldloc.0
IL_002F: ret
IL_0030: ldc.i4.2
IL_0031: stloc.0
IL_0032: ldloc.0
IL_0033: ret
IL_0034: ldc.i4.3
IL_0035: stloc.0
IL_0036: ldloc.0
IL_0037: ret
IL_0038: ldc.i4.4
IL_0039: stloc.0
IL_003A: ldloc.0
IL_003B: ret
IL_003C: ldc.i4.0
IL_003D: ret
ServiceActionType.GetHashCode:
IL_0000: nop
IL_0001: ldarg.0
IL_0002: call Microsoft.FSharp.Core.LanguagePrimitives.get_GenericEqualityComparer
IL_0007: call Query_qdoovg+ServiceActionType.GetHashCode
IL_000C: ret
ServiceActionType.Equals:
IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldnull
IL_0003: cgt.un
IL_0005: brfalse.s IL_0026
IL_0007: ldarg.1
IL_0008: isinst Query_qdoovg.ServiceActionType
IL_000D: stloc.0
IL_000E: ldloc.0
IL_000F: brfalse.s IL_0024
IL_0011: ldarg.0
IL_0012: ldfld Query_qdoovg+ServiceActionType._tag
IL_0017: stloc.1
IL_0018: ldloc.0
IL_0019: ldfld Query_qdoovg+ServiceActionType._tag
IL_001E: stloc.2
IL_001F: ldloc.1
IL_0020: ldloc.2
IL_0021: ceq
IL_0023: ret
IL_0024: ldc.i4.0
IL_0025: ret
IL_0026: ldarg.1
IL_0027: ldnull
IL_0028: cgt.un
IL_002A: ldc.i4.0
IL_002B: ceq
IL_002D: ret
ServiceActionType.Equals:
IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldnull
IL_0003: cgt.un
IL_0005: brfalse.s IL_0022
IL_0007: ldarg.1
IL_0008: ldnull
IL_0009: cgt.un
IL_000B: brfalse.s IL_0020
IL_000D: ldarg.0
IL_000E: ldfld Query_qdoovg+ServiceActionType._tag
IL_0013: stloc.0
IL_0014: ldarg.1
IL_0015: ldfld Query_qdoovg+ServiceActionType._tag
IL_001A: stloc.1
IL_001B: ldloc.0
IL_001C: ldloc.1
IL_001D: ceq
IL_001F: ret
IL_0020: ldc.i4.0
IL_0021: ret
IL_0022: ldarg.1
IL_0023: ldnull
IL_0024: cgt.un
IL_0026: ldc.i4.0
IL_0027: ceq
IL_0029: ret
ServiceActionType.Equals:
IL_0000: nop
IL_0001: ldarg.1
IL_0002: isinst Query_qdoovg.ServiceActionType
IL_0007: stloc.0
IL_0008: ldloc.0
IL_0009: brfalse.s IL_0013
IL_000B: ldarg.0
IL_000C: ldloc.0
IL_000D: call Query_qdoovg+ServiceActionType.Equals
IL_0012: ret
IL_0013: ldc.i4.0
IL_0014: ret
ServiceActionType..ctor:
IL_0000: ldarg.0
IL_0001: call System.Object..ctor
IL_0006: ldarg.0
IL_0007: ldarg.1
IL_0008: stfld Query_qdoovg+ServiceActionType._tag
IL_000D: ret
执行指令以获取堆栈上的值IL_0001: call Query_qdoovg+ServiceActionType.get_ServiceRequest
的位在哪里。call
ServiceActionType.ServiceRequest
可以像这样发出:il.Emit(OpCodes.Call, typeof<ServiceActionType>.GetMethod("get_ServiceRequest"))