【问题标题】:C# and F# casting - specifically the 'as' keywordC# 和 F# 转换 - 特别是 'as' 关键字
【发布时间】:2011-01-22 15:24:08
【问题描述】:

在 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

这是正确的吗?

【问题讨论】:

    标签: c# f# c#-to-f#


    【解决方案1】:

    据我所知,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&lt;'T&gt;,相当于C# 中的default(T))。现在你可以写了:

    let res = castAs<Type1>(inputValue)
    

    【讨论】:

    • 如果类型是静态的,这将有效。如果类型是在运行时定义的,知道该怎么做吗?我正在寻找等同于 stackoverflow.com/a/19068042/23059 的 F#。
    【解决方案2】:

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

    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
    

    【讨论】:

    • 这是不必要的...正如原始问题所指出的那样,F# 模式匹配已内置此功能。您可以| :? int as i -&gt; i
    • 这在功能上与@DanFitch 建议的使用| :? 有什么不同吗?
    • 发现了一个非常有用的区别。您可以在没有 when 子句的情况下进行 Post-cast 子匹配。以function |As(Some true) -&gt; () | _ -&gt; () 为例
    • 请注意,现在可以在 F# 6 (github.com/fsharp/fslang-design/blob/main/FSharp-6.0/…) 中进行后期匹配,因此您应该真正使用 @DanFitch 提到的内置语法
    【解决方案3】:

    您可以创建自己的运算符来执行此操作。这实际上与 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】:

      是的;见,除了以下来自: What does this C# code look like in F#? (part one: expressions and statements)

      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”会命名该类型的结果值。

      【讨论】:

      【解决方案5】:

      我想我需要为 F# 中的等价物做一个匹配表达式

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

      这对吗?

      是的,没错。 (在我看来,你自己的答案比其他答案要好。)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-02-20
        • 2011-04-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-12-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多