你能在 F# 中列出名称空间或模块的内容吗
Can you list the contents of a namespace or module in F#
类似于this question about clojure,是否可以在 F# 中列出命名空间或模块的内容?当我为加载的 DLL 打开命名空间时,我没有收到命名空间不存在的错误,但是当我尝试使用记录的函数时,我看到命名空间不存在的错误。
我正在寻找一种不依赖于 IDE 的程序化方式来列出值和方法。例如,如果我加载了 F# repl,我正在寻找类似于以下内容的内容:
> #r "mylib.DLL"
> open MyLib.Math
> list-namespace-content MyLib.Math;;
val it : string = """
MyLib.Math.Add : int -> int -> int
MyLib.Math.TryDivide : int -> int -> int option
MyLib.Math.Pi : float
"""
据我所知,没有这样的函数可以做到这一点(我看了一下 FSharpReflectionExtensions 模块),但您可以自己编写一个。所有的积木都在那里。
名称空间并不是 F#、C# 和 Visual Basic .NET 使用的 .NET 平台的一部分,这看起来可能很奇怪。在 IL 级别,类型只是 identified by name, culture, assembly, etc. 命名空间只是作为构成类型名称的字符串的第一部分出现。
但是,给定一个程序集,您可以列出其所有类型,或所有 public 类型。下面是后者的示例,给出了我最近编写的 F# 程序集来执行网球套路:
> open System.Reflection;;
> let a = Assembly.LoadFrom @"<path>\Ploeh.Katas.Tennis.PropertyBased.dll";;
val a : Assembly =
Ploeh.Katas.Tennis.PropertyBased, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
> let ts = a.GetExportedTypes();;
val ts : System.Type [] =
[|Ploeh.Katas.PropertyBased.TennisProperties;
Ploeh.Katas.PropertyBased.Tennis; Ploeh.Katas.PropertyBased.Tennis+Player;
Ploeh.Katas.PropertyBased.Tennis+Player+Tags;
Ploeh.Katas.PropertyBased.Tennis+Point;
Ploeh.Katas.PropertyBased.Tennis+Point+Tags;
Ploeh.Katas.PropertyBased.Tennis+PointsData;
Ploeh.Katas.PropertyBased.Tennis+FortyData;
Ploeh.Katas.PropertyBased.Tennis+Score;
Ploeh.Katas.PropertyBased.Tennis+Score+Tags;
Ploeh.Katas.PropertyBased.Tennis+Score+Points;
Ploeh.Katas.PropertyBased.Tennis+Score+Forty;
Ploeh.Katas.PropertyBased.Tennis+Score+Advantage;
Ploeh.Katas.PropertyBased.Tennis+Score+Game|]
通过查看最后一个 .
左侧的字符串,您可以找到正在使用的命名空间 - 在本例中为 Ploeh.Katas.PropertyBased
.
但是,您应该知道命名空间可以跨越多个程序集。例如,System.Collections.Generic.List<'T>
is defined in mscorlib
, while System.Collections.Generic.Stack<'T>
定义在 System
中。因此,如上所述使用反射只会为您提供在该特定程序集.
中的命名空间中定义的成员
据我所知,F# 模块被编译为具有 [<CompilationMapping(SourceConstructFlags.Module)>]
属性的静态 类。这意味着您可以像这样列出模块:
> open Microsoft.FSharp.Core;;
> let modules =
ts
|> Array.filter
(fun t -> t.GetCustomAttributes<CompilationMappingAttribute>()
|> Seq.exists (fun attr -> attr.SourceConstructFlags = SourceConstructFlags.Module));;
val modules : System.Type [] =
[|Ploeh.Katas.PropertyBased.TennisProperties;
Ploeh.Katas.PropertyBased.Tennis|]
如果你想列出Tennis
模块中的所有函数,你可以这样做:
> let tm = modules |> Array.find (fun t -> t.Name = "Tennis");;
val tm : System.Type = Ploeh.Katas.PropertyBased.Tennis
> let functions = tm.GetMethods ();;
val functions : MethodInfo [] =
[|Player other(Player);
Microsoft.FSharp.Core.FSharpOption`1[Ploeh.Katas.PropertyBased.Tennis+Point] incrementPoint(Point);
Point pointFor(Player, PointsData);
PointsData pointTo(Player, Point, PointsData);
Score scorePoints(Player, PointsData); Score scoreForty(Player, FortyData);
Score scoreDeuce(Player); Score scoreAdvantage(Player, Player);
Score scoreGame(Player); Score score(Score, Player); Score get_newGame();
Score scoreSeq(System.Collections.Generic.IEnumerable`1[Ploeh.Katas.PropertyBased.Tennis+Player]);
System.String pointToString(Point);
System.String scoreToString(System.String, System.String, Score);
System.String ToString(); Boolean Equals(System.Object);
Int32 GetHashCode(); System.Type GetType()|]
您可能想要过滤掉一些继承的方法,例如 ToString
和 GetHashCode
。
类似于this question about clojure,是否可以在 F# 中列出命名空间或模块的内容?当我为加载的 DLL 打开命名空间时,我没有收到命名空间不存在的错误,但是当我尝试使用记录的函数时,我看到命名空间不存在的错误。
我正在寻找一种不依赖于 IDE 的程序化方式来列出值和方法。例如,如果我加载了 F# repl,我正在寻找类似于以下内容的内容:
> #r "mylib.DLL"
> open MyLib.Math
> list-namespace-content MyLib.Math;;
val it : string = """
MyLib.Math.Add : int -> int -> int
MyLib.Math.TryDivide : int -> int -> int option
MyLib.Math.Pi : float
"""
据我所知,没有这样的函数可以做到这一点(我看了一下 FSharpReflectionExtensions 模块),但您可以自己编写一个。所有的积木都在那里。
名称空间并不是 F#、C# 和 Visual Basic .NET 使用的 .NET 平台的一部分,这看起来可能很奇怪。在 IL 级别,类型只是 identified by name, culture, assembly, etc. 命名空间只是作为构成类型名称的字符串的第一部分出现。
但是,给定一个程序集,您可以列出其所有类型,或所有 public 类型。下面是后者的示例,给出了我最近编写的 F# 程序集来执行网球套路:
> open System.Reflection;;
> let a = Assembly.LoadFrom @"<path>\Ploeh.Katas.Tennis.PropertyBased.dll";;
val a : Assembly =
Ploeh.Katas.Tennis.PropertyBased, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
> let ts = a.GetExportedTypes();;
val ts : System.Type [] =
[|Ploeh.Katas.PropertyBased.TennisProperties;
Ploeh.Katas.PropertyBased.Tennis; Ploeh.Katas.PropertyBased.Tennis+Player;
Ploeh.Katas.PropertyBased.Tennis+Player+Tags;
Ploeh.Katas.PropertyBased.Tennis+Point;
Ploeh.Katas.PropertyBased.Tennis+Point+Tags;
Ploeh.Katas.PropertyBased.Tennis+PointsData;
Ploeh.Katas.PropertyBased.Tennis+FortyData;
Ploeh.Katas.PropertyBased.Tennis+Score;
Ploeh.Katas.PropertyBased.Tennis+Score+Tags;
Ploeh.Katas.PropertyBased.Tennis+Score+Points;
Ploeh.Katas.PropertyBased.Tennis+Score+Forty;
Ploeh.Katas.PropertyBased.Tennis+Score+Advantage;
Ploeh.Katas.PropertyBased.Tennis+Score+Game|]
通过查看最后一个 .
左侧的字符串,您可以找到正在使用的命名空间 - 在本例中为 Ploeh.Katas.PropertyBased
.
但是,您应该知道命名空间可以跨越多个程序集。例如,System.Collections.Generic.List<'T>
is defined in mscorlib
, while System.Collections.Generic.Stack<'T>
定义在 System
中。因此,如上所述使用反射只会为您提供在该特定程序集.
据我所知,F# 模块被编译为具有 [<CompilationMapping(SourceConstructFlags.Module)>]
属性的静态 类。这意味着您可以像这样列出模块:
> open Microsoft.FSharp.Core;;
> let modules =
ts
|> Array.filter
(fun t -> t.GetCustomAttributes<CompilationMappingAttribute>()
|> Seq.exists (fun attr -> attr.SourceConstructFlags = SourceConstructFlags.Module));;
val modules : System.Type [] =
[|Ploeh.Katas.PropertyBased.TennisProperties;
Ploeh.Katas.PropertyBased.Tennis|]
如果你想列出Tennis
模块中的所有函数,你可以这样做:
> let tm = modules |> Array.find (fun t -> t.Name = "Tennis");;
val tm : System.Type = Ploeh.Katas.PropertyBased.Tennis
> let functions = tm.GetMethods ();;
val functions : MethodInfo [] =
[|Player other(Player);
Microsoft.FSharp.Core.FSharpOption`1[Ploeh.Katas.PropertyBased.Tennis+Point] incrementPoint(Point);
Point pointFor(Player, PointsData);
PointsData pointTo(Player, Point, PointsData);
Score scorePoints(Player, PointsData); Score scoreForty(Player, FortyData);
Score scoreDeuce(Player); Score scoreAdvantage(Player, Player);
Score scoreGame(Player); Score score(Score, Player); Score get_newGame();
Score scoreSeq(System.Collections.Generic.IEnumerable`1[Ploeh.Katas.PropertyBased.Tennis+Player]);
System.String pointToString(Point);
System.String scoreToString(System.String, System.String, Score);
System.String ToString(); Boolean Equals(System.Object);
Int32 GetHashCode(); System.Type GetType()|]
您可能想要过滤掉一些继承的方法,例如 ToString
和 GetHashCode
。