F# 类型提供程序 - 嵌套属性实例化

F# Type Providers - nested properties instantiation

我正在尝试构建我的第一个类似玩具的 Type Provider。我想要实现的是动态生成 动态生成类型 的属性。

collection 
|> getItems
|> Seq.map(fun mapItem ->            
    let nestedType = ProvidedTypeDefinition(assembly, ns, "MyNestedType", None)
    let ctor = ProvidedConstructor(List.Empty)
    nestedType.AddMember ctor
    mapItem.Value 
        |> Seq.map(fun pair -> 
        ProvidedProperty(fst(pair), typeof<string>,
            GetterCode = fun [_] -> <@@ snd(pair) @@>))
        |> Seq.toList
        |> nestedType.AddMembers


    ProvidedProperty(mapItem.Key, nestedType,
        GetterCode = fun [map] ->   
            // ?? Runtime Exception   
            let inst = nestedType.GetConstructors().[0].Invoke([||])             
            <@@ inst @@>
                ))
    |> Seq.toList
    |> ty.AddMembers      

ty

我应该如何实例化动态生成的类型?

我假设这是一个擦除类型的提供程序(这些很简单,所以它们是入门的更好选择)。如果不是这样,请无视我的回答。

GetterCode 中,您不需要创建 嵌套提供类型 的实例。您只需要创建一个类型的实例,它被擦除为

在您的情况下,nestedType 被擦除为 None,因此构造函数只需要创建一个 System.Object 值,因此您应该能够使用:

ProvidedProperty(mapItem.Key, nestedType,
    GetterCode = fun [self] -> <@@ obj() @@>)

实际上,您可能希望擦除为某种类型,以便保留嵌套类型应该访问的一些数据。如果嵌套类型被擦除为 MyRuntimeType,那么您可以这样写:

let parameter = mapItem.WhateverYouWantHere
ProvidedProperty(mapItem.Key, nestedType,
    GetterCode = fun [self] -> <@@ MyRuntimeType(parameter) @@>)

请注意,我使用 let 来捕获原始 parameter 类型的值,以便编译器可以序列化引用(您不能在引用中捕获复杂的对象类型)。

您在这里尝试做的是在构建提供程序 时实例化您的类型,然后将该新实例包含在属性 的主体中。应该非常清楚的是,您不能在完成提供类型之前实例化提供的类型。

您真正想要做的是采用您提供的构造函数并构建调用它的引用。你不能让编译器为你构建引用,因为为了让编译器编译引用的主体,它需要 "see" 全部 types/methods/functions 在里面,而你的类型还没有准备好.但是您可以使用 Quotations.Expr 下的各种构造函数手动创建报价单。在这种情况下,NewObject是合适的:

    GetterCode = fun [map] -> Expr.NewObject (ctor, [])