2016-05-13 84 views
2

比方說,我們有以下類型的無助的時刻F#泛型類型instanciation而不是鍵入

type Foo<'a,'b> = 
    new() = {} 

我們要實例化像這樣

type First = class end 

let first = new Foo<First,First>() 

而且我想要什麼現在要做的是instanciate下一個對象是類似的

let second = new Foo<first.GetType(),First>() 

但我不能做first.GetType()爲它提供一個類型。於是我想到的類型結合System.Type類型的值,並使用它像下面

let typing = first.GetType() 
let second = new Foo<typing,First>() 

但它說,該型typing沒有定義,而不是採取的first類型。 我怎樣才能做到像let second = new Foo<first.getType(),First>()這樣的事情?

編輯: 讓我們說我們有通信的協議的通道channel上: 這裏什麼我試圖瞄準的更多細節。通信協議採用類似下面的地圖定義:

[(currentState:Int , nextState:Int , type:string , label:string) -> realType:Type ] 

例如

[(currentState:1 , nextState:2 , type:"send" , label:"hello()") -> realType:Hello ; 
    (currentState:2 , nextState:3 , type:"receive" , label:"bye()") -> realType:Bye] 

我從要的是生成以下功能

send(a:Hello) 
receive(a:Bye) 

但這樣,正如您在Map中看到的,receive(a:Bye)不能在send(a:Hello)之前完成,否則在編譯時會出現錯誤。它應該遵循正確的順序。這就是爲什麼這樣做,我想實例化一個類型的類型接收類型作爲send(a:Hello)功能,允許我以下列方式使用receive(a:Bye)的返回值的原因:

channel.send(Hello()).receive(Bye()) 

的最後一件事是,該地圖可比這兩個有更多的狀態,長度取決於我使用的協議。整個想法將在一個類型提供者中實現,這樣我就可以提供我剛剛使用intelliSense描述的類型和方法。

相關問題:F# generating types in a type extension function within a type provider

+2

你不能那樣做。如果不知道類型參數是靜態的,你將如何使用這種類型? – Lee

+0

嗯,我認爲我會在類型提供者中使用它。我還認爲它可能用於類型提供程序中,並且在腳本中使用它時會編譯類型提供程序。這意味着該類型已經以某種方式定義。但現在我想到了,我將給類型提供者一個參數,然後從參數創建這些類型,所以這是不可能的。但是,這種類型的代碼只能用動態類型語言來完成,就像Python一樣嗎?你在這裏輸入參數是什麼意思? – Leleutch

+1

通過類型參數我指的是在定義「Foo」實例時爲「a」和「b」提供的類型。你必須靜態聲明這兩種類型,你用'First'做的,即'new Foo '。但'first.GetType()'返回一個表示運行時類型的對象。 Python不能代表這種關係,因爲Python根本沒有類型,但很難知道你在用這個例子做什麼。你想寫一個類型的提供者還是隻需要一個通用的數據類型? – Lee

回答

2

實例化一個泛型類型,其類型參數與已有的對象不同的實例,可以在運行時使用的方法GetGenericTypeDefinitionMakeGenericType來完成。

因此,考慮到你的例子:

type Foo<'a,'b> = 
    new() = {} 

type First = class end 

let first = new Foo<First,First>() 

的步驟是:

  1. 獲取泛型類型沒有任何類型的參數:

    let genericFooType = first.GetType().GetGenericTypeDefinition() 
    
  2. 做一個新的通用型用適當的類型參數:

    let secondType = genericFooType.MakeGenericType(first.GetType(), typeof<First>) 
    
  3. 通過適當的構造函數創建新類型的實例。在這種情況下,有一個構造函數不帶參數:

    let second = secondType.GetConstructor([||]).Invoke([||]) 
    
    second.GetType() = typeof<Foo<Foo<First,First>, First>> // True 
    

如果你需要知道的任何原始對象的類型的類型參數,就可以檢索如下:

let originalTypeArguments = first.GetType().GenericTypeArguments 

// Prints [|"First"; "First"|] 
printfn "%A" (originalTypeArguments |> Array.map (fun x -> x.Name))