2014-12-18 3 views
4

Так что я делаю простой персональный проект в winforms с F #. Мой код работал, но теперь выбрасывает это исключение по-видимому без причины.InvalidOperationException в Fsharp.Core.dll

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 example исключения you can throw on your own, а не то, что его вызывает.

+1

Не могли бы вы столкнуться с этой проблемой? http://msdn.microsoft.com/en-us/library/ms182331.aspx –

+0

Я ценю идею. У меня нет виртуальных методов, которые я вызываю из конструктора. Все они реализованы. Даже если некоторые из них в значительной степени являются владельцами мест(), как тело метода. –

+0

В коде конструктора вы передаете 'form' любому другому конструктору вашего типа? Это может вызвать исключение, которое вы видите. –

ответ

6

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() 

Один из способов может быть инкапсулировать вредоносный код, в качестве члена своей собственной и называют, что в конструкторе вместо этого. Другим было бы обертывание в определении функции.

+0

Это была проблема. Не уверен, что вы подразумеваете под инкапсулированием в этом случае. Кажется, что ни один из участников не будет полностью загружен до завершения конструктора из-за того, что нужно настраивать типы F #, разделяя его внутри другого члена и запуская его из конструктора, кажется, проблема в первую очередь. –

+1

@AlexanderRyanBaggett Пока член вызывается после «последнего значения или определения функции», вы должны быть в порядке. – kaefer

5

Это будет неполный ответ, так как я не могу воспроизвести проблему (используя F # interactive, данный пример, модификацию ReloadGoals и Form.Show, код работает нормально). Тем не менее, есть странные вещи происходят:

  • Взятые из шаблона, должен быть метод-обработчик для Form.Load event, который срабатывает, когда тип полностью построен. Почему дополнительный дополнительный код в конструкторе вместо этого обработчика событий? Load существует именно для противодействия этой проблеме с неупорядоченной инициализацией.

  • Шаблон, который вы используете, не совсем нормальный F #. Например, initControls - это значение единицы типа, которое оценивается там, где оно определено; его привязка к имени абсолютно бесполезна и должна быть заменена простым 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().) Это не так легко запускается в задачи инициализации и, кроме того, очень полезно, если вы хотите инкапсулировать форму внутри более простого типа или даже просто функции.

Смежные вопросы