Fsharp.Core.dll中的InvalidOperationException

时间:2014-12-18 11:19:05

标签: winforms f# invalidoperationexception

所以我用F#在winforms中做了一个简单的个人项目。我的代码曾经工作过,但现在抛出这个异常似乎没有理由。

An unhandled exception of type 'System.InvalidOperationException' occurred in FSharp.Core.dll

 Additional information: The initialization of an object or value resulted in an object or value being accessed recursively before it was fully initialized.

代码是从表单本身的构造函数调用的成员方法

    do
 //lots of other constructor code before this point
 // render the form
        form.ResumeLayout(false)
        form.PerformLayout()
        form.ReloadGoals



//several other members before here
    member form.ReloadGoals  =
        let x = 10  //crashes on this line

我抓住我正在使用的项目的模板的网站是this one。 不幸的是,我已经为此做了一些实质性的补充。

我很乐意发布更多代码,但我需要知道哪些代码完全相关,因为我不确定并且不想在无关代码中陷入困境。

另外,我无法在System.InvalidOperationException上找到很多文档。 每次我找到它时,它都被用作异常an exampleyou can throw on your own,而不是导致它的原因。

2 个答案:

答案 0 :(得分:7)

请参阅The F# 3.0 Language Specification (final version, PDF)§8.6.1类中的主要构造函数

  

在构造期间,在类型中的最后一个值或函数定义之前,不能调用该类型的成员   已完成;这样的调用会导致 InvalidOperationException。

几乎可以肯定,问题中的代码并不能说明完整的故事。如果你碰到了上面的话 提到限制,然后在某处尝试访问未完全初始化的字段或成员。

一些例子:

type X() as this =
    let x = this.X
    member __.X = 42
X()

一种解决方法可能是将有问题的代码封装在自己的成员中,而是在构造函数中调用它。另一个是函数定义中的包装。

答案 1 :(得分:5)

这将是一个不完整的答案,因为我无法重现问题(使用F#interactive,给定示例,ReloadGoals修改和Form.Show,代码运行正常)。然而,发生了奇怪的事情:

  • 从模板中获取Form.Load event应该有一个处理程序方法,该方法在完全构造类型时触发。为什么构造函数中的其他加载代码而不是此事件处理程序? Load正是为了解决这种无序初始化问题而存在的。

  • 您使用的模板并非完全正确的F#。例如,initControls是类型unit的值,在定义它的位置进行计算;它与名称的绑定绝对没用,应该用简单的do替换。稍后在initControls块中写do根本没有效果。 form.ResumeLayout(false); form.PerformLayout()应该等同于form.ResumeLayout(true),但我一开始并不了解这些在构造函数中的作用。事件处理程序有两个可能不必要的间接:一个是委托构造函数,另一个是没有真正理由存在的方法 - 处理程序应该是lambdas或简单的私有函数。他们为什么是公共会员?!

问题中出现的错误可能是由form在其自己的构造函数中使用引起的。将新用法移至Load事件处理程序,它应该可以正常工作。

就个人而言,我会更进一步,通过实例化一个普通的Form并订阅它的事件来抛弃实现继承。例如,在FSI中,类似于模板的东西可以这样做:

open System.Drawing
open System.Windows.Forms

let form = new Form()
form.ClientSize <- new Size(600, 600)
form.Text <- "F# Form"

let formLabel = new Label()
formLabel.Text <- "Doubleclick test!"
formLabel.DoubleClick.Add <| fun _ -> form.Close() 
form.Controls.Add(formLabel)

form.Show()

根本不使用继承。 (在应用程序中,您使用Application.Run等而不是form.Show()。)这不会很容易地遇到初始化问题,另外,如果要将表单封装在内部,则非常有用更简单的类型,甚至只是一个函数。