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

3

我正在尝试构建我的第一个类似玩具的类型提供程序。我的目标是拥有动态生成的动态生成类型的属性。

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个回答

3
我假设这是一个擦除型提供程序(它们比较简单,因此更适合入门)。如果不是这种情况,请忽略我的回答。
在`GetterCode`中,您不需要创建`nested provided type`的实例。您只需要创建它被擦除为的类型的实例。
在您的情况下,`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类型的值,以便编译器可以序列化引用(您不能在引用中捕获复杂对象类型)。

谢谢,我现在明白擦除类型是如何工作的了。问题是,在类型提供程序编译时,我不知道属性的名称,所以如果我没记错的话,我只能将其擦除为object类型。 - mickl
我想要实现的只是像这样的东西:providedType.dynamically_generated_prop.dynamically_generated_prop_nested,在使用提供者时。 - mickl

0

你在这里尝试做的是在构建提供程序的同时实例化你的类型,并将该新实例包含在属性的主体中。显然,你不能在提供类型之前实例化它。

你真正想做的是使用提供的构造函数构建一个调用它的引用。你不能让编译器为你构建引用,因为为了编译引用的主体,编译器需要“看到”其中的所有类型/方法/函数,而你的类型还没有准备好。但是你可以通过使用Quotations.Expr下的各种构造函数手动创建引用。在这种情况下,NewObject是合适的:

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

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