【问题标题】:How can I hide methods in F#?如何在 F# 中隐藏方法?
【发布时间】:2011-01-05 05:10:25
【问题描述】:

我目前正在用 F# 实现一个 Spec 框架,我想在我的 should 类型上隐藏 Equals、GetHashCode 等方法,这样 API 就不会被这些弄乱。

我知道在 C# 中它是通过让类实现这样的接口来完成的:

using System;
using System.ComponentModel;

public interface IFluentInterface
{
    [EditorBrowsable(EditorBrowsableState.Never)]
    bool Equals(object other);

    [EditorBrowsable(EditorBrowsableState.Never)]
    string ToString();

    [EditorBrowsable(EditorBrowsableState.Never)]
    int GetHashCode();

    [EditorBrowsable(EditorBrowsableState.Never)]
    Type GetType();
}

我尝试在 F# 中做同样的事情:

type IFluentInterface = interface

    [<EditorBrowsable(EditorBrowsableState.Never)>]
    abstract Equals : (obj) -> bool

    [<EditorBrowsable(EditorBrowsableState.Never)>]
    abstract ToString: unit -> string

    [<EditorBrowsable(EditorBrowsableState.Never)>]
    abstract GetHashCode: unit -> int

    [<EditorBrowsable(EditorBrowsableState.Never)>]
    abstract GetType : unit -> Type 
end

在我的类型中实现它:

        interface IFluentInterface with
        member x.Equals(other) = x.Equals(other)
        member x.ToString()    = x.ToString() 
        member x.GetHashCode() = x.GetHashCode()
        member x.GetType()     = x.GetType() 

但没有成功。

我还尝试覆盖我的类型中的方法并以这种方式添加属性,但这也没有成功。

所以问题仍然存在,我该如何清理我的 API?

编辑:

感谢帮助(见下文),我能够解决我的问题。

总之,.Equals.GetHashCode 可以通过 [&lt;NoEquality&gt;] [&lt;NoComparison&gt;] 隐藏,但这也会改变语义。

通过 EditorBrowsable 属性隐藏不起作用。

拥有干净的 API 并且仍然能够重载方法的唯一方法是使这些方法成员静态。

通过浏览我的项目FSharpSpec,可以找到生成的类。

有问题的类型可以找到here.

感谢所有帮助我解决这个问题的人。

干杯...

【问题讨论】:

    标签: api f#


    【解决方案1】:

    或者,您可以使用包含在模块中的函数使用另一种样式来设计库。这是在 F# 中编写 功能 代码的常用方法,您无需隐藏任何标准 .NET 方法。为了完成'kvb'给出的示例,这里是一个面向对象的解决方案示例:

    type MyNum(n:int) =
      member x.Add(m) = MyNum(n+m)
      member x.Mul(m) = MyNum(n*m)
    
    let n = new MyNum(1)
    n.Add(2).Mul(10) // 'ToString' shows in the IntelliSense
    

    编写代码的函数式方式可能如下所示:

    type Num = Num of int
    module MyNum =
      let create n = Num n
      let add m (Num n) = Num (m + n)
      let mul m (Num n) = Num (m * n)
    
    MyNum.create 1 |> MyNum.add 2 |> MyNum.mul 10
    

    如果您键入MyNum.,F# IntelliSense 将显示模块中定义的函数,因此在这种情况下您不会看到任何噪音。

    【讨论】:

    • 我会调查一下,我认为这种方法也可以让我重载方法? -- 另一方面,我喜欢你在 F# 上的屏幕投射。
    • 谢谢!不幸的是,使用let 声明的函数不能被重载。仅member 声明支持重载。请参阅有关 F# 中重载的其他 SO 问题 - 例如stackoverflow.com/questions/2260939/f-overloading-functions
    • 那么在这种情况下我需要使用一个类型,因为我严重依赖于重载方法的能力,你可以想象一个 should.contain(actual, expected) 需要以不同的方式实现例如,对于字符串而不是序列。是否可以重载静态成员?显然,如果我将我的 Assertion 类及其成员设为静态,它就不会显示任何 .ToString() ... 方法。
    • 谢谢,我将它们全部更改为静态,现在得到了我清理的 API(请参阅我的问题的编辑)。
    【解决方案2】:

    重复我的回答

    http://cs.hubfs.net/forums/thread/13317.aspx

    在 F# 中,您可以通过使用 NoEquality 和 NoComparison 属性注释类型来禁止 Equals 和 GetHashCode(并将它们从智能感知中删除),如下所示。用户定义的方法也可以通过 Obsolete 属性或 IsHidden=true 的 CompilerMessage 属性从智能感知列表中隐藏。无法从 F# 智能感知中隐藏 System.Object 方法 GetType 和 ToString。

    [<NoEquality; NoComparison>]
    type Foo() =
        member x.Bar() = ()
        member x.Qux() = ()
        [<System.Obsolete>]
        member x.HideMe() = ()
        [<CompilerMessage("A warning message",99999,IsError=false,IsHidden=true)>]
        member x.WarnMe() = ()
    
    let foo = new Foo()
    foo.  // see intellisense here
    

    【讨论】:

    • 谢谢,Brian 我应用了这个更改来稍微清理它。如我所见,您发现两个地方都是我问的问题(我涵盖了我的基础)。现在我要考虑 Tomas 方法,因为他是正确的,我不需要使用类型,模块就可以了。
    【解决方案3】:

    我认为 F# 通常没有任何方法可以做到这一点。在.Equals.GetHashCode 的特殊情况下,您可以通过在您的类型上放置[&lt;NoEquality&gt;] 属性来使它们不可用,但这实际上除了隐藏这些方法之外还具有语义效果。

    编辑

    还可能值得一提的是,F# 中很少使用流畅的接口,因为使用组合器和流水线来代替它更为惯用。例如,假设我们想要创建一种创建算术表达式的方法。而不是

    let x = Expressions.MakeExpr(1).Add(2).Mul(3).Add(4)
    

    我认为大多数 F# 用户更愿意编写

    open Expressions
    let x = 
      1
      |> makeExpr
      |> add 2
      |> mul 3
      |> add 4
    

    使用这种样式,无需隐藏成员,因为表达式通过管道传递给组合器,而不是调用表达式构建器的方法。

    【讨论】:

    • 谢谢,我还必须添加 [] 属性,我这样做了。在这种情况下,受影响的语义无关紧要。仍然需要隐藏 ToString() 和 GetType(),但是看起来已经干净多了。
    • @ "fluent 接口在 F# 中很少使用" 对不起,这个名字可能会引起误解,我这个接口的唯一目的是隐藏上面提到的方法。我只是碰巧经常使用这种接口在 C# 中创建流畅的接口。
    猜你喜欢
    • 1970-01-01
    • 2016-07-10
    • 2010-10-17
    • 1970-01-01
    • 2011-10-08
    • 2011-08-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多