2011-07-12 119 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