Мне не известно об эквиваленте FSharpType.MakeTupleType для записей и объединений в библиотеке F #.
Один из способов создания структур записи или объединения типа во время выполнения - использовать Reflection.Emit. Тип записи аналогичен закрытому классу, а тип объединения - это абстрактный базовый класс с закрытыми классами для каждого случая.
Например, следующая функция генерирует минимальное 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>|])
Обратите внимание, что ожидаемые интерфейсы для типа записи могут также должны быть сгенерированы, то есть реализации IEquatable, IStructuralEquatable, IComparable и IStructuralComparable отсутствуют ,
Update
Методы расширения MakeTupleType и MakeUnionType на основе образца кода выше, теперь доступны в открытом источнике Fil (F # к IL Compiler) проекта (альфа).
Возможный дубликат [Создание записи F # через отражение] (http://stackoverflow.com/questions/8139223/creating-f-record-through-reflection) – Daniel
@ daniel приведенный ниже пример действительно завершен и полезен для запуска point – hmwill