У меня есть много модулей, которые при запуске программы должны добавлять определенные вещи в один словарь, находящийся в модуле более высокого уровня. Однако оказывается, что выражения и константы внутри модуля упаковываются в статические конструкторы при компиляции в консольное приложение, поэтому они не оцениваются, если на них явно не ссылаются/когда программа считает, что они необходимы.
Здесь было несколько вопросов относительно инициализации модулей, и все согласны с тем, что это невозможно принудительно. Однако я не видел, чтобы кто-либо из них исследовал рефлексию в этом отношении. Я знаю, что в C# вы можете вызывать статический конструктор типа, поэтому я попытался сделать то же самое с модулями F#.
Мои попытки включали добавление настраиваемого атрибута (MessageHandlerAttribute) в каждый модуль, содержащий такое выражение, которое я хочу оценить при запуске программы, а затем запустить это:
let initAllMessageHandlerModules =
Assembly.GetExecutingAssembly().GetTypes()
|> Array.choose (fun typ ->
typ.CustomAttributes
|> Seq.tryFind (fun attr -> attr.AttributeType = typeof<MessageHandlerAttribute>)
|> Option.map (fun _ -> typ))
|> Array.iter
(fun typ -> try typ.TypeInitializer.Invoke(null, null) |> ignore with | ex -> printfn "%A" ex)
Но это дает мне следующую ошибку: System.NullReferenceException: ссылка на объект не указывает на экземпляр объекта.
Я также попытался поменять последнюю лямбда-функцию следующим образом:
(fun typ -> try System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(typ.TypeHandle) |> ignore with | ex -> printfn "%A" ex)
Но это, кажется, ничего не делает. Можно ли этого добиться?
Seq.tryFind
, аSeq
оцениваются лениво - может быть проблема в этом? - person LSM07   schedule 16.03.2019