2016-04-22 120 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, [])