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

时间:2016-04-22 06:12:20

标签: f# type-providers quotations

我正在尝试建立我的第一个类似玩具的类型提供商。我想要实现的是动态生成动态生成类型的属性。

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

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

2 个答案:

答案 0 :(得分:3)

我假设这是一个擦除类型的提供者(那些是容易的,所以他们是入门的更好选择)。如果情况并非如此,那么请忽略我的答案。

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类型的值,以便编译器可以序列化引用(您无法在引号中捕获复杂对象类型)。

答案 1 :(得分:0)

您在此处尝试执行的操作是在构建提供程序时实例化您的类型,然后在属性的主体中包含该新实例。应该非常清楚的是,在您完成提供之前,您无法实例化所提供的类型。

您真正想要做的是获取您提供的构造函数并构建一个调用它的引用。你不能让编译器为你构建报价,因为为了让编译器编译报价的主体,它需要&#34;参见&#34;内部所有类型/方法/功能,您的类型尚未准备好。但您可以使用Quotations.Expr下的各种构造函数手动创建报价。在这种情况下,NewObject是合适的:

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