在F#中创建记录类型

3
我希望基于提供的字段创建一个简单的记录类型。
也就是说:
let rectype = MakeRecordType(['fieldname1'; 'fieldname2'])

直接使用类型提供程序似乎对于这样一个简单的任务来说有些过于浪费。

还有其他方法吗?

更新

我发现了下面这个问题,它看起来非常相似 通过反射创建F#记录


2
我不明白,你如何使用一个动态创建的记录类型?与此相反的是:type MyRecord = { field1: string, field2: string} - yamen
@yamen 我会和其他类型一样使用它。 - nicolas
涉及的软件是由纽约市市长制作的一款小型黑客软件。 - nicolas
它不仅仅是动态类型:它是反静态类型。 - nicolas
3
只需使用 Dictionary<> 就可以完成。 - ildjarn
显示剩余7条评论
1个回答

7

暂且不论最终结果的有用性,在下面的代码片段中,如我的其他相关回答所述,完全实现了你的要求:

#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的草图实现接受一个任意的记录类型定义,其中包含类型名称和一组字段名称,并伴随着字段类型名称。然后,在幕后它会组装一段F#代码来定义所请求的记录类型,通过CodeDom提供程序编译这段代码,加载容器程序集,并通过反射提供对这个新创建的合成记录类型的访问。下面是一个测试片段:

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|]

相当酷。尽管如此,我很惊讶,因为我在2005年就在C#中使用了相同的花哨技巧来获取动态LINQ查询。7年后,我们在可组合类型创建方面几乎处于同一位置... - nicolas
1
@nicolas:F#和C#都是静态类型语言。运行时类型创建并不简单或内置,这是有原因的。 - ildjarn
@ildjam 实际上,静态/动态类型的概念是不完整的。需要说在谁的眼中是静态/动态。因此,这两个概念本身非常渗透。 - nicolas
@ildjarn,你完全正确,但这是一个真理。我很惊讶这个(方便的)静态类型的神话在现实方面发展如此之少。 - nicolas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接