动态转换为接口

时间:2011-07-12 16:18:56

标签: f#

根据帖子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()

是否有更优雅的方式来编写上述代码。我想创建另一个运算符来替换:?&gt;,但我无法获得传入的泛型类型参数,如:?&gt;

2 个答案:

答案 0 :(得分:6)

您的cast函数的行为与C#as运算符不同 - 如果对象无法转换为指定类型,则会抛出异常而不是返回null。因此,检查italk = null是否完成任何操作。如果你想使cast函数在转换失败而不是抛出异常时返回null,你可以像这样写:

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代替您的空测试。

答案 1 :(得分: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()