最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

Error in F# 9.0 on singleton pattern: The static initialization of a file or type resulted in static data being accessed recursi

programmeradmin3浏览0评论

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
  • 2 It works on my machine with 9.0.100 so its probably not a direct "can't possibly work anymore" thing. Often adding a type annotation can help. Also why mutable, if anything it should be readonly? Its possible that rules around that will decide whether the code can go into a static constructor block or not. So e.g.: static let instance: Lazy<AEM> = lazy AEM() – Ruben Bartelink Commented Feb 17 at 9:24
  • @RubenBartelink Thanks. Please look at the Edit. Thank you. – Alan Wayne Commented Feb 17 at 15:49
  • @RubenBartelink Yep, that's it. Please post as answer. – Alan Wayne Commented Feb 17 at 18:36
  • That must have been very frustrating, I feel your pain! I had a wild guess of a direction - you figured it out, go accept your self-answer ;) (Can you post a larger snippet though, i.e. was the mutable not relevant, and the option attempt seems confusing ?) – Ruben Bartelink Commented Feb 17 at 21:44
Add a comment  | 

1 Answer 1

Reset to default 1

After 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.

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论