有没有办法让以下代码有效?
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") // ...
你可以在所有几何中重复使用普通成员(圆形,椭圆形......)
答案 0 :(得分: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)
答案 1 :(得分:3)
在.NET(以及扩展名为F#)中,您需要初始化一个对象,然后才能调用它上面的任何方法或将其传递给另一个方法。因此,在将对象传递给基础构造函数Line
之前,需要初始化<{1}}对象。但是在调用基础构造函数之前无法对其进行初始化,因此没有直接的方法来执行您想要的操作。
话虽如此,F#有一个系统可以在定义之前捕获非法递归使用值,所以我很惊讶你没有得到更有意义的异常,而不是Geometry<Line>(self)
(或者更好的是,编译时错误)。比较一下,如果您尝试使用以下定义调用NullReferenceException
会发生什么:
new Rec()
解决这个问题的一种方法是应使用懒惰来延迟使用type Rec(r:Rec) =
new() as self = Rec(self)
标识符:
self
可悲的是,这不起作用,进一步证实了在这种情况下检查初始化稳健性存在F#错误的理论。幸运的是,这可以通过使用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
的显式构造函数而不是主构造函数来解决:
Line
答案 2 :(得分: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