从F#生成类型提供程序提供的类型继承

4

我有一个基本的生成式F#类型提供程序

[<TypeProvider>]
type MyTypeProvider(config : TypeProviderConfig) as this = 
    inherit TypeProviderForNamespaces(config)

    let ns = "MyNamespace"
    let asm = Assembly.LoadFrom(config.RuntimeAssembly)

    let buildTypes (typeName:string) (args:obj[]) =
        let asm = ProvidedAssembly()
        let srvName = args.[0] :?> string
        ... omitted
        let provided = ProvidedTypeDefinition(asm, ns, typeName, Some typeof<MyRuntimeType>, hideObjectMethods = true, nonNullable = true, isErased = false)
        let ctor = ProvidedConstructor([], (fun _ -> <@@ MyRuntimeType() @@>))
        provided.AddMember(ctor)
        provided
    let parameters = 
        [ ProvidedStaticParameter("Host", typeof<string>, "") ]

    let provider = ProvidedTypeDefinition(asm, ns, "MyProvider", Some typeof<obj>, hideObjectMethods = true, nonNullable = true, isErased = false)
    do provider.DefineStaticParameters(parameters, buildTypes)
    do this.AddNamespace(ns, [provider])

[<assembly:TypeProviderAssembly()>]
do ()

在另一个项目中,我想通过继承提供的类型来使用它,而不是直接使用该类型:
type Provided = MyNamespace.MyProvider<"Host123">

type Derived() = 
    inherit Provided() //Cannot inherit a sealed type

然而,我遇到了一个错误,提示提供的类型是密封类,因此无法继承。

这是设计上的问题还是我漏掉了什么?

1个回答

3

这是F#类型提供程序SDK中的默认行为。您可以在ProvidedTypes.fs文件的ProvidedTypeDefinition类中查看用于提供类型定义的属性(大约位于1241-1252行附近):

    static let defaultAttributes isErased = 
        TypeAttributes.Public ||| 
        TypeAttributes.Class ||| 
        TypeAttributes.Sealed ||| 
        enum (if isErased then int32 TypeProviderTypeAttributes.IsErased else 0)

你可以通过在构造函数的第五个参数中显式地传递TypeAttributes来覆盖此设置(您将需要使用接受所有参数的构造函数)。在省略部分结束后,代码看起来像这样:
let derivableClassAttributes = TypeAttributes.Public ||| TypeAttributes.Class

let provided = 
    ProvidedTypeDefinition(false, 
                           TypeContainer.Namespace (K asm,ns), 
                           typeName, 
                           K (Some typeof<MyRuntimeType>), 
                           derivableClassAttributes, 
                           K None, 
                           [], 
                           None, 
                           None, 
                           K [||], 
                           true, 
                           true)

不幸的是,它无法工作。主构造函数未被编译器识别(因为fsi文件没有声明它,我猜测)。此外,例如,第二个参数使用了类型TypeContainer,该类型使用RequireQualifiedAccessAttribute声明,因此我应该使用完整名称“ProviderImplementation.ProvidedTypes.TypeContainer.Namespace(K asm,ns)”,但即使如此,编译器也无法识别它(我认为是出于同样的原因)。因此,您建议的解决方案在技术上是正确的,但是不能在不调整SDK源代码的情况下使用。 - Franco Tiveron

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