In F# FSharp.Core(8.0.400) and Windows .NetCore 3.1, the following singleton pattern worked flawlessly:
[<AutoOpen>]
module AppointmentEventManager
open Stargate.XI.Client.Domain.Models
type public AEM private() =
let appointmentEvent = new Event<Appointment option>()
let cellEvent = new Event<Cell>()
static let mutable instance = lazy(new AEM())
static member Instance with get() = instance.Value
[<CLIEvent>]
member x.AppointmentEvent = appointmentEvent.Publish
member x.RaiseAppointmentEvent(arg) = appointmentEvent.Trigger(arg)
// these members are public.
// CellEvent -- used by ColumnModule (Column.fs) to tell Registration.fs what is current selected cell/appointment
[<CLIEvent>]
member x.CellEvent = cellEvent.Publish
member x.RaiseCellEvent(arg) = cellEvent.Trigger(arg)
it was used from C# as:
private void Appointments_Loaded(object sender, RoutedEventArgs e)
{
AppointmentEventManager = AEM.Instance;
AppointmentEventManager.AppointmentEvent += cellSelected;
}
However, when moving to FSharp.Core (9.0.201)
and net6.0-windows, it fails with error of:
System.InvalidOperationException: 'The static initialization of a file or type resulted in static data being accessed recursively before it was fully initialized.
This occurs on "instance.Value".
Nothing I can think of has gotten arround this error.
Any help is greatly appreciated.
Edit#1.
Ok, figure this out. When recompiled into a "Class Library" project, not as "F# Library", the above code loses 4 of my other 13 projects saying it "can't find them". However, the below code works great!
type AEM private () =
static let instanceLock = obj()
static let mutable instance: AEM option = None
let appointmentEvent = new Event<Appointment option>()
let cellEvent = new Event<Cell>()
static member GetInstance() =
lock instanceLock (fun () ->
if instance.IsNone then
instance <- Some (AEM())
)
instance.Value
[<CLIEvent>]
member x.AppointmentEvent = appointmentEvent.Publish
member x.RaiseAppointmentEvent(arg) = appointmentEvent.Trigger(arg)
[<CLIEvent>]
member x.CellEvent = cellEvent.Publish
member x.RaiseCellEvent(arg) = cellEvent.Trigger(arg)
Any Ideas?
In F# FSharp.Core(8.0.400) and Windows .NetCore 3.1, the following singleton pattern worked flawlessly:
[<AutoOpen>]
module AppointmentEventManager
open Stargate.XI.Client.Domain.Models
type public AEM private() =
let appointmentEvent = new Event<Appointment option>()
let cellEvent = new Event<Cell>()
static let mutable instance = lazy(new AEM())
static member Instance with get() = instance.Value
[<CLIEvent>]
member x.AppointmentEvent = appointmentEvent.Publish
member x.RaiseAppointmentEvent(arg) = appointmentEvent.Trigger(arg)
// these members are public.
// CellEvent -- used by ColumnModule (Column.fs) to tell Registration.fs what is current selected cell/appointment
[<CLIEvent>]
member x.CellEvent = cellEvent.Publish
member x.RaiseCellEvent(arg) = cellEvent.Trigger(arg)
it was used from C# as:
private void Appointments_Loaded(object sender, RoutedEventArgs e)
{
AppointmentEventManager = AEM.Instance;
AppointmentEventManager.AppointmentEvent += cellSelected;
}
However, when moving to FSharp.Core (9.0.201)
and net6.0-windows, it fails with error of:
System.InvalidOperationException: 'The static initialization of a file or type resulted in static data being accessed recursively before it was fully initialized.
This occurs on "instance.Value".
Nothing I can think of has gotten arround this error.
Any help is greatly appreciated.
Edit#1.
Ok, figure this out. When recompiled into a "Class Library" project, not as "F# Library", the above code loses 4 of my other 13 projects saying it "can't find them". However, the below code works great!
type AEM private () =
static let instanceLock = obj()
static let mutable instance: AEM option = None
let appointmentEvent = new Event<Appointment option>()
let cellEvent = new Event<Cell>()
static member GetInstance() =
lock instanceLock (fun () ->
if instance.IsNone then
instance <- Some (AEM())
)
instance.Value
[<CLIEvent>]
member x.AppointmentEvent = appointmentEvent.Publish
member x.RaiseAppointmentEvent(arg) = appointmentEvent.Trigger(arg)
[<CLIEvent>]
member x.CellEvent = cellEvent.Publish
member x.RaiseCellEvent(arg) = cellEvent.Trigger(arg)
Any Ideas?
Share Improve this question edited Feb 17 at 15:48 Alan Wayne asked Feb 16 at 22:07 Alan WayneAlan Wayne 5,39412 gold badges59 silver badges101 bronze badges 4 |1 Answer
Reset to default 1After spending the weekend over this, the answer is as @RubenBartelink suggested. i.e, its not "lazy(new AEM()), but rather "lazy AEM()". All works now.
static let instance: Lazy<AEM> = lazy AEM()
– Ruben Bartelink Commented Feb 17 at 9:24