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