在运行时创建F#记录或联合类型(不是其实例)

在运行时创建F#记录或联合类型(不是其实例),f#,f#-3.0,F#,F# 3.0,在运行时创建代表F#记录或联合的System.Type实例的最佳方法是什么?也就是说,我正在为记录和联合寻找与FSharpType.MakeTupleType等效的文件 我只是想澄清一下,我对创建实例(即FSharpValue.MakeRecord或FSharpValue.MakeUnion)不感兴趣。我不知道F#库中记录和联合的等效实例 在运行时创建类似于记录或联合类型的结构的一种方法是使用。记录类型类似于密封类,联合类型是抽象基类,每种情况下都有密封类 例如,以下函数生成最小F#记录类型:

在运行时创建代表F#记录或联合的System.Type实例的最佳方法是什么?也就是说,我正在为记录和联合寻找与FSharpType.MakeTupleType等效的文件


我只是想澄清一下,我对创建实例(即FSharpValue.MakeRecord或FSharpValue.MakeUnion)不感兴趣。

我不知道F#库中记录和联合的等效实例

在运行时创建类似于记录或联合类型的结构的一种方法是使用。记录类型类似于密封类,联合类型是抽象基类,每种情况下都有密封类

例如,以下函数生成最小F#记录类型:

open System
open System.Reflection
open System.Reflection.Emit

let MakeRecord(typeName:string, fields:(string * Type)[]) =
    let name = "GeneratedAssembly"
    let domain = AppDomain.CurrentDomain
    let assembly = domain.DefineDynamicAssembly(AssemblyName(name), AssemblyBuilderAccess.RunAndSave)
    let name = "GeneratedModule"
    let dm = assembly.DefineDynamicModule(name, name+".dll")
    let attributes = TypeAttributes.Public ||| TypeAttributes.Class ||| TypeAttributes.Sealed
    let typeBuilder = dm.DefineType(typeName, attributes)
    let con = typeof<CompilationMappingAttribute>.GetConstructor([|typeof<SourceConstructFlags>|])
    let customBuilder = CustomAttributeBuilder(con, [|SourceConstructFlags.RecordType|])
    typeBuilder.SetCustomAttribute(customBuilder)
    let makeField name t =
        let attributes = FieldAttributes.Assembly
        let fieldBuilder = typeBuilder.DefineField(name+"@", t, attributes)
        let attributes = PropertyAttributes.None
        let propertyBuilder = typeBuilder.DefineProperty(name, attributes, t, [||])
        let customBuilder = CustomAttributeBuilder(con, [|SourceConstructFlags.Field|])
        propertyBuilder.SetCustomAttribute(customBuilder)
        let attributes = MethodAttributes.Public ||| MethodAttributes.HideBySig ||| MethodAttributes.SpecialName
        let methodBuilder = typeBuilder.DefineMethod("get_"+name, attributes, t, [||])
        let il = methodBuilder.GetILGenerator()
        il.Emit(OpCodes.Ldarg_0)
        il.Emit(OpCodes.Ldfld, fieldBuilder)
        il.Emit(OpCodes.Ret)
        propertyBuilder.SetGetMethod(methodBuilder)
        fieldBuilder
    let types = fields |> Array.map snd
    let cb = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, types)
    let il = cb.GetILGenerator()
    il.Emit(OpCodes.Ldarg_0)
    il.Emit(OpCodes.Call, typeof<obj>.GetConstructor(Type.EmptyTypes))
    fields |> Array.iteri (fun i (name, t) -> 
        let paramName = name.Substring(0,1).ToLower()+name.Substring(1)
        let param = cb.DefineParameter(i+1, ParameterAttributes.In, paramName)
        let fieldBuilder = makeField name t
        il.Emit(OpCodes.Ldarg_0)
        il.Emit(OpCodes.Ldarg, param.Position)
        il.Emit(OpCodes.Stfld, fieldBuilder)
    )
    il.Emit(OpCodes.Ret)
    let t = typeBuilder.CreateType()
    assembly.Save("GeneratedModule.dll")
    t

let r = MakeRecord("MyRecord", [|"Alpha",typeof<int>;"Beta",typeof<string>|])
开放系统
开放系统。反射
开放系统.Reflection.Emit
let MakeRecord(类型名称:string,字段:(string*Type)[]))=
让name=“GeneratedAssembly”
让域=AppDomain.CurrentDomain
让assembly=domain.definedDynamicAssembly(AssemblyName(name),AssemblyBuilderAccess.RunAndSave)
let name=“GeneratedModule”
设dm=assembly.definedDynamicModule(名称,名称+“.dll”)
让attributes=TypeAttributes.Public | | | TypeAttributes.Class | | | TypeAttributes.Sealed
让typeBuilder=dm.DefineType(类型名、属性)
设con=typeof.GetConstructor([| typeof |])
让customBuilder=CustomAttributeBuilder(con,[| SourceConstructFlags.RecordType |])
typeBuilder.SetCustomAttribute(customBuilder)
让makeField命名为t=
let attributes=FieldAttributes.Assembly
让fieldBuilder=typeBuilder.DefineField(名称+“@”,t,属性)
让attributes=PropertyAttributes.None
让propertyBuilder=typeBuilder.DefineProperty(名称、属性、t、[| |])
让customBuilder=CustomAttributeBuilder(con,[| SourceConstructFlags.Field |])
propertyBuilder.SetCustomAttribute(customBuilder)
让attributes=MethodAttributes.Public | | | MethodAttributes.hidebysing | | | MethodAttributes.SpecialName
让methodBuilder=typeBuilder.DefineMethod(“get|”+名称,属性,t,[| |])
设il=methodBuilder.GetILGenerator()
il.Emit(操作码.Ldarg_0)
il.Emit(操作码.Ldfld,fieldBuilder)
il.Emit(操作码Ret)
propertyBuilder.SetGetMethod(methodBuilder)
现场建设者
让types=fields |>Array.map snd
设cb=typeBuilder.DefineConstructor(MethodAttributes.Public,CallingConventions.Standard,types)
设il=cb.GetILGenerator()
il.Emit(操作码.Ldarg_0)
Emit(opcode.Call,typeof.GetConstructor(Type.EmptyTypes))
fields |>Array.iteri(fun i(name,t)->
设paramName=name.Substring(0,1).ToLower()+name.Substring(1)
设param=cb.DefineParameter(i+1,ParameterAttributes.In,paramName)
让fieldBuilder=makeField name t
il.Emit(操作码.Ldarg_0)
il.Emit(操作码.Ldarg,参数位置)
il.Emit(操作码.Stfld,fieldBuilder)
)
il.Emit(操作码Ret)
设t=typeBuilder.CreateType()
Save(“GeneratedModule.dll”)
T
设r=MakeRecord(“MyRecord”[|“Alpha”,typeof;“Beta”,typeof |])
注:可能还需要生成记录类型的预期接口,即缺少IEquatable、IsstructuralEquatable、IComparable和IsstructuralComparable的实现

更新


基于上述代码示例的扩展方法MakeTupletType和MakeUnionType现已在开源(F#to IL编译器)项目(alpha)中提供。

可能重复@daniel下面给出的示例实际上已经完成,一个有用的起点CodePlex正在关闭,此答案链接到
Fil
,有新的回购协议吗?