如何在构造函数中抛出异常?

时间:2013-01-15 23:34:13

标签: f#

如果我这样做是不合理的

type Point = 
    struct
        val Row: int
        val Column: int

        new (row, column) = if row >= 0 && column >= 0 then { Row = row; Column = column }
                            else failwith "Cooridinators must be non-negative!" 
        // This is not a valid object construction
        static member (+) (x: Point, y: Point) = Point (x.Row + y.Row, x.Column + y.Column)
        static member (-) (x: Point, y: Point) = Point (x.Row - y.Row, x.Column - y.Column)
        static member (*) (x: Point, a) = Point (x.Row * a, x.Column * a)
        static member (*) (a, x: Point) =  Point (x.Row * a, x.Column * a)
    end

如果它是一个类,那么我可以在do绑定期间引发异常,但在结构中没有do,我该怎么办?

我发现可以在failwith之后添加另一个构造函数来解决这个问题,但它引发了另一个问题,我怎样才能调用隐式构造函数?我是否必须首先明确地构建它,如

new () = { Row = 0; Column = 0} 
// Error structs auto supports a default constructor

如果我只使用默认构造函数

执行此操作
new (row, column) = if row >= 0 && column >= 0 then { Row = row; Column = column }
                    else
                        failwith "Cooridinators must be non-negative!"
                        new Point () // error

在我看来Point ()会返回一个单位而不是Point

3 个答案:

答案 0 :(得分:8)

我认为F#编译器会抱怨因为构造函数应该总是有一个结构:

  

new ( 模式 ) = 表达式 { 初始化 } [then 表达式 ]

因此,初始化字段的部分不能嵌套在if下或任何其他表达式中。您可以在初始化之前或之后(如果添加then关键字)抛出异常。 (这对于具有继承的类很重要,但我认为它对结构没有任何影响。)

因此,编写代码的一种方法是编写:

type Point = 
    struct
        val Row: int
        val Column: int

        new (row, column) = 
          if row < 0 || column < 0 then failwith "Cooridinators must be non-negative!"
          { Row = row; Column = column }          

        // (Static members omitted)
    end

请注意,我必须否定条件,因为您需要在要抛出异常时指定大小写(而不是说何时可以构造对象)。另一种选择是:

new (row, column) = 
  { Row = row; Column = column }          
  then if row < 0 || column < 0 then failwith "Cooridinators must be non-negative!"

答案 1 :(得分:4)

您还有另一种方法可以在初始化部分中抛出异常:

new (row, column) = 
  { Row = ((if row < 0 || column < 0 then failwith "Coordinators must be non-negative!"); row); 
    Column = column }

请记住,验证结构构造函数并不总是一个好主意。如您所知,您无法控制默认构造函数的初始化。如果它是一个类,您可以确保以您希望的方式验证所有构造函数。

答案 2 :(得分:0)

这是一个古老的问题。但是,没有任何答案提到这一点:我认为惯用的F#方式是根本不抛出异常!为此,您可以使用static member tryCreate,如果满足所有条件,则返回Some Point,如果出现问题则返回None。然后,您将遵循选项类型的踪迹来编写逻辑代码,而不用处理异常!我也认为F#记录可能也是一种惯用的方式,除非您出于某些非常特定的目的明确需要使用struct。