2016-04-22 34 views
3

我正在尝试构建我的第一个类似玩具的类型提供程序。我试图实现的是动态生成属性动态生成类型F#类型提供者 - 嵌套属性实例化

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 

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

回答

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

+0

谢谢,我现在明白擦除类型如何工作。问题是,我不知道类型提供程序编译时的属性名称,所以如果我没有错,我只能删除对象。 – mickl

+0

我试图达到的目的只有这样:providedType.dynamically_generated_prop.dynamically_generated_prop_nested,当消费提供者 – mickl

0

你在这里要做的是在建立提供者的同时实例化你的类型,然后在属性的主体中包含新的实例。应该非常清楚的是,在完成提供之前,您不能实例化提供的类型。

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

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