Оценка статических конструкторов модулей с отражением - PullRequest
1 голос
/ 14 марта 2019

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

Здесь возникло несколько вопросов, касающихся инициализации модулей, и был достигнут консенсус в отношении того, что его невозможно форсировать. Тем не менее, я не видел, чтобы кто-нибудь из них исследовал рефлексию в этом отношении. В 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)

Но это, похоже, ничего не делает. Можно ли этого добиться?

1 Ответ

0 голосов
/ 03 апреля 2019

Используйте type.GetConstructor вместо type.TypeInitializer.

(fun typ -> try typ.GetConstructor(BindingFlags.Instance ||| BindingFlags.Public, null, CallingConventions.Standard, Array.empty<Type>, Array.empty<ParameterModifier>).Invoke(null, null) |> ignore with | ex -> printfn "%A" ex)

Здесь еще несколько примеров

...