You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

F#如何在编译时从字符串生成简单空类型?

解决F#静态参数类型提供器的调用错误:生成编译时字符串指定的嵌套类型

我明白你想实现的目标——通过类型提供器在编译时从输入字符串生成一个同名的空类型(比如记录、联合或简单类类型),但目前卡在了脚本调用的语法错误上。咱们先拆解问题,一步步解决。

首先看你遇到的错误:

The non-generic type 'SimpleStringProvider.SingleStringTypeProvider' does not expect any type arguments, but here is given 1 type argument(s)

这个错误的核心原因是混淆了泛型类型参数和类型提供器静态参数的语法:F#中,泛型类型用尖括号<>传递参数,而类型提供器的静态参数是用括号()传递的,编译器把你用<>"test"的写法当成了泛型参数传递,自然会报错。

第一步:修正类型提供器实现

我们先调整类型提供器的代码,确保它能正确生成嵌套的空类型(这里以简单类为例,你可以换成记录或联合类型):

module SimpleStringProvider

open ProviderImplementation.ProvidedTypes
open Microsoft.FSharp.Core.CompilerServices
open System.Reflection

[<TypeProvider>]
type SingleStringTypeProvider(config: TypeProviderConfig) as this =
    inherit TypeProviderForNamespaces(config)
    
    let asm = Assembly.GetExecutingAssembly()
    let ns = "SimpleStringProvider"
    
    // 定义类型提供器的根类型(本身是非泛型的)
    let rootProvider = 
        ProvidedTypeDefinition(asm, ns, "SingleStringTypeProvider", Some(typeof<obj>))
    
    do
        // 定义静态参数:接收一个字符串作为要生成的嵌套类型名称
        let typeNameParam = ProvidedStaticParameter("TypeName", typeof<string>)
        
        // 处理静态参数,生成具体的类型实例
        rootProvider.DefineStaticParameters(
            [typeNameParam],
            fun generatedTypeName args ->
                // 获取传入的字符串参数
                let nestedTypeName = args.[0] :?> string
                
                // 创建主类型(对应你示例中的`Provided`)
                let mainType = ProvidedTypeDefinition(asm, ns, generatedTypeName, Some(typeof<obj>))
                
                // 创建嵌套的空类型:这里可以换成ProvidedRecordType或ProvidedUnionType
                let nestedType = ProvidedTypeDefinition(nestedTypeName, None)
                // 如果你要生成空记录类型,替换成:
                // let nestedType = ProvidedRecordType(nestedTypeName, None)
                // 如果你要生成空联合类型,替换成:
                // let nestedType = ProvidedUnionType(nestedTypeName, None)
                
                // 将嵌套类型添加到主类型中
                mainType.AddMember(nestedType)
                
                // 返回最终生成的类型
                mainType
        )
        
        // 将根类型注册到命名空间
        this.AddNamespace(ns, [rootProvider])

[<assembly: TypeProviderAssembly>]
do ()

第二步:修正脚本调用语法

把脚本里的尖括号改成括号,用正确的静态参数传递方式:

#r @".\testType\SimpleStringProvider.dll"
open SimpleStringProvider

// 用()传递静态参数,而非<>
type Provided = SingleStringTypeProvider("One")

// 验证生成的类型
let typeName = typeof<Provided.One>.Name // 编译时就能获取到"One"
printfn "Generated type name: %s" typeName

关键注意点

  • 确保你的类型提供器项目已安装FSharp.TypeProviders.SDK NuGet包,这是使用ProvidedTypes等API的前提。
  • 如果你需要生成记录/联合类型,只需要把ProvidedTypeDefinition换成对应的ProvidedRecordType或ProvidedUnionType即可,空类型的话不需要额外添加字段或case。
  • 生成的Provided.One是编译时存在的类型,完全符合你“在编译时是一个类型而非方法/函数”的需求。

内容的提问来源于stack exchange,提问作者jkone27

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 07:02:08