您可以在F#中列出名称空间或模块的内容吗 [英] Can you list the contents of a namespace or module in F#

查看:113
本文介绍了您可以在F#中列出名称空间或模块的内容吗的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

类似于关于Clojure的问题,是吗?可能在F#中列出名称空间或模块的内容?当我为已加载的DLL打开命名空间时,我没有收到该命名空间不存在的错误,但是当我尝试使用已记录的函数时,却看到该命名空间不存在的错误.

Similar to this question about clojure, is it possible to list the contents of a namespace or module in F#? When I open a namespace for a loaded DLL I'm not receiving an error that the namespace doesn't exist, but then when I try to use the documented functions I'm seeing errors that the namespace doesn't exist.

我正在寻找一种列出值和方法的编程方式,而不是依赖于IDE.例如,如果我加载了F#repl,我正在寻找类似于以下内容的东西:

I'm looking for a programatic way of listing values and methods and not relying on the IDE. For example if I loaded up the F# repl I'm looking for something similar to:

> #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
   """

推荐答案

据我所知,没有这样的功能可以做到这一点(我浏览了

As far as I know, there's no such function that does exactly that (I had a glance at the FSharpReflectionExtensions module), but you can write one yourself. All the building blocks are there.

看起来很奇怪,名称空间不是F#,C#和Visual Basic .NET都使用的.NET平台的一部分.在IL级别,类型只是通过名称,文化,程序集来标识等等.命名空间只是出现在构成类型名称的字符串的第一部分.

As strange as it may seem, namespaces aren't part of the .NET platform that both F#, C#, and Visual Basic .NET use. At the IL level, types are simply identified by name, culture, assembly, etc. Namespaces simply appear as the first part of the string that makes up a type's name.

但是,给定程序集,您可以列出其所有类型或所有公共类型.这是后者的一个例子,考虑到我最近写的一个F#程序集,它是在Tennis kata上编写的:

However, given an assembly, you can list all its types, or all its public types. Here's an example of the latter, given an F# assembly I recently wrote doing the Tennis kata:

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

By looking at the strings to the left of the last ., you can find the namespace(s) in use - in this case Ploeh.Katas.PropertyBased.

但是,您应该注意,名称空间可以跨多个程序集.例如,在mscorlib中定义了 System.Collections.Generic.List<'T> System.Collections.Generic.Stack<'T> System中定义.因此,如上所述使用Reflection仅将为您提供在该特定程序集中的名称空间 中定义的成员.

However, you should be aware that namespaces can span multiple assemblies. As an example, System.Collections.Generic.List<'T> is defined in mscorlib, while System.Collections.Generic.Stack<'T> is defined in System. Thus, using Reflection as above will only give you the members defined in a namespace in that particular assembly.

据我所知,F#模块使用[<CompilationMapping(SourceConstructFlags.Module)>]属性编译为静态类.这意味着您可以像这样列出模块:

As far as I know, F# modules are compiled to static classes with the [<CompilationMapping(SourceConstructFlags.Module)>] attribute. This means that you can list the modules like this:

> 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模块中的所有功能,可以这样做:

If you want to list all the functions in the Tennis module, you can do that like this:

> 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()|]

您可能希望过滤掉某些继承的方法,例如ToStringGetHashCode.

You may want to filter out some of the inherited methods, like ToString and GetHashCode.

这篇关于您可以在F#中列出名称空间或模块的内容吗的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆