2

我想根据提供的字段制作一个简单的记录类型。

那是 :

let rectype = MakeRecordType(['fieldname1'; 'fieldname2'])

对于这样一个简单的任务,直接去找类型提供者看起来像是强大的火力。

还有其他方法吗?

更新

我发现以下问题看起来非常相似 通过反射创建 F# 记录

4

1 回答 1

5

撇开最终结果的有用性不谈,下面的片段完全按照我的其他相关答案的精神实现了您所要求的:

#if INTERACTIVE
#r @"C:\Program Files (x86)\Microsoft F#\v4.0\FSharp.Compiler.dll"
#r @"C:\Program Files (x86)\FSharpPowerPack-1.9.9.9\bin\FSharp.Compiler.CodeDom.dll"
#endif

open System 
open System.CodeDom.Compiler 
open Microsoft.FSharp.Compiler.CodeDom
open Microsoft.FSharp.Reflection

type RecordTypeMaker (typeName: string, records: (string*string) []) = 
    let _typeDllName = "Synth"+typeName+".dll"
    let _code = 
        let fsCode = new System.Text.StringBuilder()
        fsCode.Append("module ").Append(typeName).Append(".Code\ntype ").Append(typeName).Append(" = {") |> ignore
        for rec' in records do fsCode.Append("  ").Append(fst rec').Append(" : ").Append(snd rec').Append(";\n") |> ignore
        fsCode.Append("}").ToString()
    let _compiled =
        use provider = new FSharpCodeProvider() 
        let options = CompilerParameters([||], _typeDllName) 
        let result = provider.CompileAssemblyFromSource( options, [|_code|] ) 
        result.Errors.Count = 0
    let mutable _type: Type = null

    member __.RecordType
        with get() = if _compiled && _type = null then
                         _type <- Reflection.Assembly.LoadFrom(_typeDllName).GetType(typeName+".Code+"+typeName)
                     _type

的草图实现RecordTypeMaker接受一个任意Record type定义,其中包含和type name的数组field namesfield type names然后在幕后组装一段定义请求的 Record 类型的 F# 代码,通过 编译此代码CodeDom provider,加载容器程序集并通过 Reflection 提供对这个新创建的合成 Record 类型的访问。一个测试片段

let myType = RecordTypeMaker("Test", [|("Field1", "string"); ("Field2", "int")|]).RecordType
printfn "IsRecordType=%b" (FSharpType.IsRecord(myType))
printfn "Record fields: %A" (FSharpType.GetRecordFields(myType))

为纯合成类型演示myType概念证明:

IsRecordType=true
Record fields: [|System.String Field1; Int32 Field2|]
于 2012-04-14T17:40:03.320 回答