#c# #.net #f#
#c# #.net #f#
Вопрос:
В настоящее время существует класс F #, реализованный следующим образом:
namespace MultiLanguage.FSharpClassLibrary
open MultiLanguage.CSharpClassLibrary
open System
open System.Runtime.Serialization
[<Serializable>]
type SerializableFSharpClass =
inherit SerializableBaseClass
new () as this =
{ inherit SerializableBaseClass() }
then
this.InitFields()
new (other: SerializableFSharpClass) as this =
{ inherit SerializableBaseClass(other) }
then
this.InitFields()
// Copy Properties
new (info : SerializationInfo, context : StreamingContext) as this
= { inherit SerializableBaseClass(info, context) } then
this.InitFields()
// Deserialize Properties
// Let binding does not work
// because of the following error:
// FS0963: This definition may only be used in a type with a primary constructor.
//let myFSharpEvent = new Event<EventHandler<EventArgs>,EventArgs>()
//[<CLIEvent>]
//member this.FSharpEvent = myFSharpEvent.Publish
// Event raising does not work with member private
// because new instances are created with every access to FSharpEvent:
//member private this.myFSharpEvent = new Event<EventArgs>()
//[<CLIEvent>]
//member this.FSharpEvent = this.myFSharpEvent.Publish
//member this.RaiseFSharpEvent e = this.myFSharpEvent.Trigger e
// Event raising works with val mutable
// but requires additional initialization of myFSharpEvent
[<DefaultValue>]
val mutable myFSharpEvent : Event<EventHandler<EventArgs>,EventArgs>
[<CLIEvent>]
member this.FSharpEvent = this.myFSharpEvent.Publish
member this.RaiseFSharpEvent e = this.myFSharpEvent.Trigger e
member private this.InitFields()
=
this.myFSharpEvent <- new Event<EventHandler<EventArgs>,EventArgs>()
Мне интересно, есть ли более простой способ заставить оба CLIEvent работать с привязкой let и по-прежнему использовать все конструкторы базового класса по мере необходимости, чтобы окончательно избавиться от метода InitFields .
Ответ №1:
Боюсь, здесь вы мало что можете сделать. Проблема в том, что облегченный синтаксис F # для классов с неявным конструктором может использоваться только в том случае, если вы всегда вызываете только один конструктор базового класса. В вашей ситуации это не так, и поэтому вы должны использовать явный синтаксис.
Вы можете избежать DefaultValue
атрибута, если инициализируете событие в { .. }
части конструктора, где вы можете вызвать конструктор базового класса, а также инициализировать все поля. На самом деле это вам не очень помогает, но это единственная настройка, о которой я могу думать:
type A =
new (n:int) = {}
new (s:string) = {}
type B =
inherit A
new (n:int) = {
inherit A(n)
myFSharpEvent = new Event<_, _>() }
new (s:string) = {
inherit A(s)
myFSharpEvent = new Event<_, _>() }
val mutable myFSharpEvent : Event<EventHandler<EventArgs>,EventArgs>
member this.FSharpEvent = this.myFSharpEvent.Publish
member this.RaiseFSharpEvent e = this.myFSharpEvent.Trigger e
Это приводит к некоторому минимальному дублированию кода — я думаю, это нормально, но вы также можете определить вспомогательную функцию (но вне класса, потому что вы не можете использовать let
в этом классе).
Итог, вероятно, заключается в том, что я бы убрал всю важную логику из этого класса и рассматривал это только как оболочку, чтобы сделать мой хороший код F # совместимым с любой необходимой вам инфраструктурой .NET.