4

有什么办法可以使下面的代码工作?

open System.Collections.Generic

type Geometry<'t>(child: 't) =
  let values = List()
  member o.add (v: float) = values.Add v; child

and Line() as self =
  inherit Geometry<Line>(self)
  member o.length v = o.add v

let line = Line().length(50.0)

我明白了

System.NullReferenceException:对象引用未设置为对象的实例。

编辑:

调用以下代码来触发异常就足够了。

let line = Line()

动机是您可以执行以下操作:

let line = Line().x1(10).y1(20).x2(30).y2(10).color("blue") // ...

并且您可以在所有几何图形(圆形、椭圆形、...)中重用公共成员

4

3 回答 3

5
open System.Collections.Generic

type Geometry<'t when 't :> Geometry<'t>>() =
  let values = List()
  member o.add (v: float) = values.Add v; o :?> 't

and Line() =
  inherit Geometry<Line>()
  member o.length v = o.add v

let line = Line().length(50.0)
于 2013-05-03T18:57:18.223 回答
3

在 .NET(以及扩展名 F#)中,您需要先初始化一个对象,然后才能对其调用任何方法或将其传递给另一个方法。因此,您的Line对象需要在传递给基本构造函数之前Geometry<Line>(self)进行初始化。但它不能在调用基本构造函数之前被初始化,所以没有直接的方法来做你想做的事。

话虽如此,F# 有一个系统应该在定义值之前捕获非法递归使用的值,所以我很惊讶你没有得到更有意义的异常而不是NullReferenceException(或者更好的是,编译时错误)。例如,比较如果您尝试new Rec()使用以下定义调用会发生什么:

type Rec(r:Rec) =
    new() as self = Rec(self)

解决此问题的一种方法是应该使用惰性来延迟self标识符的使用:

type Geometry<'t>(child: Lazy<'t>) =
  let values = List()
  member o.add (v: float) = values.Add v; child.Value

and Line() as self =
  inherit Geometry<Line>(lazy self)
  member o.length v = o.add v

遗憾的是,这不起作用,这进一步证明了在这种情况下检查初始化健全性时存在 F# 错误的理论。幸运的是,这可以通过使用显式构造函数Line代替主构造函数来解决:

type Geometry<'t>(child: Lazy<'t>) =
  let values = List()
  member o.add (v: float) = values.Add v; child.Value

and Line =
  inherit Geometry<Line>
  new() as self = { inherit Geometry<Line>(lazy self) }
  member o.length v = o.add v
于 2013-05-03T19:57:15.697 回答
1

关于 F# 需要注意的一件事——它的主要特性之一是它非常简洁(尤其是与 C# 或 Java 相比)。但是,根据我的经验,尝试使代码尽可能简洁也很容易忘乎所以。相反,您最好以编写尽可能简洁实用的代码为目标。

我提出这个问题的原因是因为您使用分号将多个语句放在一行 - 它通过保存一两个换行符使代码更短,但缺点是它不能很好地与 VS 调试器配合使用.

如果您删除了对分号的使用,您应该能够在有问题的行上放置断点,然后使用 VS 调试器(或 MonoDevelop / Xamarin Studio)单步执行它们。明确知道哪个语句导致抛出异常可以更容易地确定问题的原因。

如果您尝试此操作并且能够识别有问题的线路,请将该信息添加到您的问题中,我们将能够为您提供更好的答案。

type Geometry<'t> (child: 't) =
  let values = ResizeArray ()
  member o.add (v: float) =
    values.Add v
    child

and Line () as self =
  inherit Geometry<Line> (self)
  member o.length v =
    o.add v

let line =
    let l = Line ()
    l.length 50.0
于 2013-05-03T19:30:00.600 回答