根据类型选择BitConverter.ToXXX函数

时间:2013-10-22 11:53:53

标签: generics f# higher-order-functions

我通常会尝试使我的问题更通用,但这次我认为示例案例使问题更加清晰。我也是F#的新手,所以在这个阶段尝试概括太多可能是一个错误:)

我想要实现的是创建一个函数,该函数返回给定类型参数的相应BitConverter.ToXXX函数。这是我试过的:

let FromBytes<'a> : (byte[] * int -> 'a) = 
  match typeof<'a> with
  | x when x = typeof<Int16> -> BitConverter.ToInt16
  | x when x = typeof<UInt16> -> BitConverter.ToUInt16
  | _ -> failwith "Unknown type"

但是,这会失败,因为编译器不理解类型是否保证匹配。

我确信我可以找到解决方法,但有没有办法在不更改功能签名的情况下完成这项工作?

1 个答案:

答案 0 :(得分:4)

您需要投射最终值:

let FromBytes<'a> : (byte[] * int -> 'a) = 
  match typeof<'a> with
  | x when x = typeof<Int16>  -> downcast (BitConverter.ToInt16  |> box)
  | x when x = typeof<UInt16> -> downcast (BitConverter.ToUInt16 |> box)
  | _ -> failwith "Unknown type"

这将在运行时检查类型并选择正确的大小写,在编译时使用静态约束也有一个技巧,但是如果你正在学习它可能真的很混乱:

open System
type T = T with
    static member ($) (T, _: int16) = fun v s -> BitConverter.ToInt16 (v,s)
    static member ($) (T, _:uint16) = fun v s -> BitConverter.ToUInt16(v,s)
    static member ($) (T, _: int  ) = fun v s -> BitConverter.ToInt32 (v,s)
    static member ($) (T, _:uint32) = fun v s -> BitConverter.ToUInt32(v,s)

let inline fromBytes (value:byte[], startIndex:int) = 
    (T $ Unchecked.defaultof< ^R>) value startIndex : ^R

// usage
let (x:int   ) = fromBytes([|255uy;0uy;0uy;255uy|], 0)
let (y:uint16) = fromBytes([|255uy;0uy;0uy;255uy|], 0)

F#编译器在调用站点内联所需的函数,不能从C#调用泛型函数。