2011-07-12 93 views
2

根據帖子http://cs.hubfs.net/forums/thread/3616.aspx, 我需要使用類似下面的函數來將一個對象轉換爲一個接口,我已經運行了一個測試,這仍然是真的,錯誤:?>仍然是不固定。動態轉換爲接口

let cast<'a> o = (box o) :?> 'a 
let ci = { new Customer(18, Name = "fred") with 
       override x.ToString() = x.Name 
      interface ITalk with 
       member x.Talk() = 
        printfn "talk1111111" } 

let italk = cast<ITalk> ci 

if not (italk = null) then 
    italk.Talk() 

是否有更優雅的方式來編寫上述代碼。我正在考慮創建另一個運算符來替換:?>,但我無法獲取傳入的泛型類型參數,如:?>

回答

6

您的cast函數的行爲不像C#as運算符 - 如果對象可以' t被轉換爲指定的類型,它會拋出一個異常而不是返回null。因此,檢查italk = null是否完成任何操作。如果你想使cast函數返回空當轉換失敗,而不是拋出一個異常,你可以寫這樣的:

let cast<'a when 'a : null> o = 
    match box o with 
    | :? 'a as output -> output 
    | _ -> null 

然而,這隻能在可空類型的工作,不包括結構或(默認情況下)F#類型。我可能會按照原樣離開您的cast功能,並且使用選項製作tryCast

let tryCast<'a> o = 
    match box o with 
    | :? 'a as output -> Some output 
    | _ -> None 

然後,你可以使用這樣的:

ci |> tryCast<ITalk> |> Option.iter (fun it -> it.Talk()) 

在這種情況下,Option.iter需要你的空測試的地方。

+0

我創建了一個操作符 「!>」,如下所示 令O =(框○):>「一個 讓ITX:的iTalk => CI itx.Talk() 但缺點是,作爲將被輸入作爲標識符的註釋,類型沒有!編譯時檢查。無法編譯的 –

2

模式匹配提供了寫這更習慣的方法:

match box ci with 
| :? ITalk as italk -> italk.Talk() 
| _ ->() 

或者,甚至:

let bci = box ci 
if bci :? ITalk then (bci :?> ITalk).Talk() 

我一直像一個函數圍繞以下,因爲當我知道這種測試將持有:(!>)

let coerce value = (box >> unbox) value 

(coerce ci : ITalk).Talk() 
+0

。 –

+0

@Fred:對不起,輸入到瀏覽器中。由於根據實現的第一種類型輸入對象表達式,因此仍然需要調用「box」。我修復了代碼。 – Daniel

+0

@Fred:我用另一個選項更新了我的答案,可以在你的情況下工作。 – Daniel