【问题标题】:How to declare a generic exception type in F#如何在 F# 中声明泛型异常类型
【发布时间】:2018-10-03 02:59:21
【问题描述】:

如何定义如下异常?

exception CustomExn<'TMessage> of 'TMessage list

【问题讨论】:

  • 根据F# Spec(第 164 页,第 8.11 页)我认为不可能做到这一点,可能是提案的好人选
  • 我有一半希望在某处找到一个指南,说带有泛型类型参数的异常是不明智的,但我没有找到一个。我仍然会说最好避免使用它们 - 您可能并不真正需要有关异常的详细信息,如果需要,您可能正在查看正常的控制流而不是异常路径。
  • @scrwtp:我用它来将第三方库的一元输出转换为异常。这是一个用例示例:stackoverflow.com/questions/49956854/…

标签: generics exception f#


【解决方案1】:

也许您可以只从 System.Exception 继承?

type CustomExn<'TMessage> (message:'TMessage list) =
    inherit System.Exception ()  

let test =
    try
        raise (CustomExn["string"] )
    with 
    | :? CustomExn<string> -> "CustomExn of string"
    | :? CustomExn<int> -> "CustomExn of int"
    | _ ->  "Everything else"

【讨论】:

  • try with with 子句中不起作用,因为它不是通用的
  • 好吧,在您的回答中,您的做法完全一样。当您指定关闭的异常类型时,它会被 try/with 捕获。
  • 是的,因为您需要为每个封闭类型定义非泛型 exn 定义。那么泛型的全部意义就消失了。
  • 在您的情况下,您必须知道您的方法可能抛出的确切类型的封闭泛型(这不在函数签名中),否则您将丢失消息列表。正如我所说,最好的方法是使用Result&lt;'a, 'b list&gt;
【解决方案2】:

根据specs(第 164-165 页),不确定 F# Exception Definitions 是否可行

这个也不是一个好的解决方案,因为try with 在这种情况下只会捕获ExceptionList&lt;string&gt;,所以没有好的方法让它通用

type ExceptionList<'a>(msgList: 'a list) =
    inherit Exception()
    member __.MessageList = msgList

let mock() = 
    raise <| ExceptionList(["failed"])

try
    mock() //raises ExceptionList<string>
with
    //this catch block won't fire, because it is not generic, it is ExceptionList<obj>
    | :? ExceptionList<_> as exnList -> 
        exnList.MessageList 
        |> List.iter (printfn "%A")

不过更好的方法是:Result&lt;'a,'b list&gt;:

let mock'() = 
    if DateTime.Now.Ticks % 2L = 0L 
    then Ok()
    else Error(["failed"])

let result = mock'()
match result with
| Ok _ -> printfn "Ok!"
| Error (msgList) -> 
      msgList
      |> List.iter (printfn "%A")

添加有一种解决类型丢失的方法:

type ExceptionList(msgList: obj list) =
    inherit Exception()
    member __.MessageList = msgList

// Here is F# exception definition
exception CustomException of ExceptionList

let failwithMany msgs = 
    raise <| CustomException (ExceptionList(msgs))

let mock() =
    //zero type checking here
    failwithMany[1;2;"a";[];"failed"]

try
    mock()
with
    // exnList is list of objects
    | CustomException exnList ->
        exnList.MessageList 
        |> List.iter (printfn "%A")

【讨论】:

    猜你喜欢
    • 2012-01-15
    • 2023-04-01
    • 2011-09-28
    • 2012-02-06
    • 1970-01-01
    • 2015-12-14
    • 2018-12-14
    • 1970-01-01
    • 2019-04-02
    相关资源
    最近更新 更多