C#和F#中的转换 - 特别是'as'关键字

33

在C#中我可以这样做:

var castValue = inputValue as Type1

在 F# 中,我可以这样做:

let staticValue = inputValue :> Type1
let dynamicValue = inputValue :?> Type1

但是两者都不等同于C#中的关键字as

我猜我需要在F#中使用匹配表达式来找到相应的等效方式。

match inputValue with
| :? Type1 as type1Value -> type1Value
| _ -> null

这是正确的吗?

5个回答

37
据我所知,F#没有任何内置运算符与C#的as相等,因此您需要编写一些更复杂的表达式。除了使用match的代码之外,您还可以使用if,因为运算符:?可以像C#中的is一样使用:
let res = if (inputValue :? Type1) then inputValue :?> Type1 else null

当然,您可以编写一个函数来封装此行为(通过编写一个简单的通用函数,将Object转换为指定的泛型类型参数):

let castAs<'T when 'T : null> (o:obj) = 
  match o with
  | :? 'T as res -> res
  | _ -> null

这种实现会返回null,因此要求类型参数具有null作为适当的值(或者,您可以使用Unchecked.defaultof<'T>,它等同于C#中的default(T))。现在,您只需编写:

let res = castAs<Type1>(inputValue)

如果类型是静态的,这个方法可以工作。如果类型在运行时被定义了,你有什么想法吗?我正在寻找 F# 版本的 https://dev59.com/83M_5IYBdhLWcg3wUxVB#19068042。 - Cameron Taggart

14

我建议使用主动模式。这是我使用的一个:

let (|As|_|) (p:'T) : 'U option =
    let p = p :> obj
    if p :? 'U then Some (p :?> 'U) else None

以下是 As 的示例用法:

代码示例:

let handleType x = 
    match x with
    | As (x:int) -> printfn "is integer: %d" x
    | As (s:string) -> printfn "is string: %s" s
    | _ -> printfn "Is neither integer nor string"

// test 'handleType'
handleType 1
handleType "tahir"
handleType 2.
let stringAsObj = "tahir" :> obj
handleType stringAsObj

4
这是不必要的……因为原问题已经指出,F#模式匹配内置了此功能。你可以使用 | :? int as i -> i - Dan Fitch
这个功能与@DanFitch建议使用|:?有什么不同吗? - Maslow
4
发现一个非常有用的区别。你可以在没有when子句的情况下进行后缀匹配。例如,function |As(Some true) -> () | _ -> () - Maslow
1
请注意,F# 6 现在可以进行后置匹配了(https://github.com/fsharp/fslang-design/blob/main/FSharp-6.0/FS-1105-Non-variable-patterns-to-the-right-of-as-patterns.md),如 @DanFitch 所提到的,因此您应该真正使用内置语法。 - chkn

6

您可以创建自己的操作符来实现这一点。这与Tomas的示例几乎完全相同,但展示了一种稍微不同的调用方式。以下是一个示例:

let (~~) (x:obj) = 
  match x with
  | :? 't as t -> t //'
  | _ -> null

let o1 = "test"
let o2 = 2
let s1 = (~~o1 : string)  // s1 = "test"
let s2 = (~~o2 : string) // s2 = null

4
是的,除了以下内容: 这段C#代码在F#中是什么样子?(第一部分:表达式和语句) C#有"is"和"as"运算符用于类型测试。 F#在匹配模式中使用特定的模式来实现这一点。 因此,这段C#代码:
    if (animal is Dog)
    {
        Dog dog = animal as Dog;
        // …
    }
    else if (animal is Cat)
    {
        Cat cat = animal as Cat;
        // …
    }

变成了这段 F# 代码:
    match animal with
    | :? Dog as dog -> // …
    | :? Cat as cat -> // …

其中“:? type”是类型测试,“as ident”命名了该类型测试成功后的结果值。

你的答案在另一个城堡里:何时一个答案不是一个答案?这是一个链接式回答,而不是指向另一个stackoverflow详细回答的链接。 - Maslow

1
我想我需要在F#中使用match表达式来找到相应的内容。
使用以下代码: match inputValue with | :? Type1 as type1Value -> type1Value | _ -> null 这样做是正确的。 (在我看来,你自己的答案比其他答案更好。)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接