我正在编写一个程序,我必须将一些obj类型的输入验证为数字类型。基本上,我正在寻找函数
validateint : obj -> int option
validatefloat : obj -> float option
... and so on
本身这不是问题,例如,我有类似的东西:
let validateint x =
match x with
| y when y.GetType() = typeof<int> -> y :?> int |> Some
| y when y.GetType() = typeof<float> -> y :?> float |> int |> Some
| y when y.GetType() = typeof<System.Int16> -> y :?> System.Int16 |> int |> Some
/// ...more numeric cases
| _ -> None
然而,在为validateint编写类似的代码之后,我想把一个将转换函数作为输入的函数分解出来,如:
let validatenumeric cast x =
match x with
| y when y.GetType() = typeof<int> -> y :?> int |> cast |> Some
| y when y.GetType() = typeof<float> -> y :?> float |> cast |> Some
| y when y.GetType() = typeof<System.Int16> -> y :?> System.Int16 |> cast |> Some
/// ...more numeric cases
| _ -> None
然后定义
let validateint = validatenumeric int
let validatefloat = validatenumeric float
...
但是,这不起作用,因为F#基本上推断了int的类型 - &gt; 'a然后第二个和后面的匹配案例输入不正确。我想我可以通过为浮点数为每个数字类型添加一个额外的强制转换来避免这种情况,但这感觉就像一个丑陋的黑客。有更优雅的解决方案吗?
答案 0 :(得分:4)
我认为您不需要自己重新实现这些功能。 .NET中的System.Convert
类型已提供尝试将任何输入转换为指定类型的操作,如果无法完成转换,则会失败。
let validateNumeric<'T> input =
try Some(System.Convert.ChangeType(input, typeof<'T>) :?> 'T)
with _ -> None
以下是F#Interactive输出示例:
> validateNumeric<int> (box 1.1);;
val it : int option = Some 1
> validateNumeric<float> "1.1";;
val it : float option = Some 1.1
> validateNumeric<float> "xxx";;
val it : float option = None
一个不幸的事情是没有方法不会抛出异常 - 所以如果你需要转换数千个值,这对你来说可能太慢了。
答案 1 :(得分:2)
你需要使用泛型类型,试试这个
let validate<'a, 'b> (cast: 'a -> 'b) (x: 'a) =
try
cast x |> Some
with _ -> None
let a = validate int "123"
let b = validate int 1.23
let c = validate float "abc"
let d = validate<obj, decimal> Convert.ToDecimal (null :> obj)
let e = validate<string, DateTime> Convert.ToDateTime "2013-9-21"
答案 2 :(得分:0)
open System
let validateint =function
|(x:obj) when x=null->None
| :? int as i->Some(i)
| :? float as f->Some(f|>int)
| :? string as s->Int32.TryParse(s)|>function |true,x->Some(x)|_->None
//| :? ...
|_->None