Ответ 1
Вы можете реализовать это с помощью .NET Reflection. Локальные переменные и функции определяются как статические свойства/методы типов в одной динамической сборке. Вы можете получить эту сборку, вызвав GetExecutingAssembly
(в самом FSI), а затем просмотрите типы, чтобы найти все подходящие свойства.
Ниже приведена разумно работающая функция для получения локальных переменных:
open System.Reflection
open System.Collections.Generic
let getVariables() =
let types = Assembly.GetExecutingAssembly().GetTypes()
[ for t in types |> Seq.sortBy (fun t -> t.Name) do
if t.Name.StartsWith("FSI_") then
let flags = BindingFlags.Static ||| BindingFlags.NonPublic |||
BindingFlags.Public
for m in t.GetProperties(flags) do
yield m.Name, lazy m.GetValue(null, [||]) ] |> dict
Вот пример:
> let test1 = "Hello world";;
val test1 : string = "Hello world"
> let test2 = 42;;
val test2 : int = 42
> let vars = getVariables();;
val vars : System.Collections.Generic.IDictionary<string,Lazy<obj>>
> vars.["test1"].Value;;
val it : obj = "Hello world"
> vars.["test2"].Value;;
val it : obj = 42
Функция возвращает "ленивое" значение назад (потому что это был самый простой способ записать его без предварительного считывания значений всех переменных, что было бы медленным), поэтому вам нужно использовать свойство Value
. Также обратите внимание, что вы получаете object
назад - потому что система типа F # не знает тип - вам придется использовать ее динамически. Вы можете получить все имена, просто итерации по vars
...