2010-03-05 3 views
5

В настоящее время я реализую структуру Spec в F #, и я хочу скрыть методы Equals, GetHashCode и т. Д. На моем should типах, чтобы API не был загроможден этими.Как скрыть методы в F #?

Я знаю, что в 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?

Edit:

Благодаря помощи (смотри ниже) я был в состоянии решить мою проблему.

В целом, .Equals и .GetHashCode могут быть скрыты с помощью [<NoEquality>][<NoComparison>] но это будет также изменить семантику.

Скрытие с помощью атрибутов EditorBrowsable не работает.

Единственный способ иметь чистый API и по-прежнему иметь возможность перегружать методы состоит в том, чтобы сделать эти члены метода статическими.

Полученный класс можно найти, просмотрев мой проект FSharpSpec.

рассматриваемого типа можно найти here.

Спасибо всем, кто помог мне решить эту проблему.

Приветствия ...

ответ

4

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

+0

Я рассмотрю это, я предполагаю, что этот подход также позволит мне перегрузить методы? - На другой ноте я наслаждался вашими экранами на F #. –

+0

Спасибо! К сожалению, функции, объявленные с использованием 'let', не могут быть перегружены. Перегрузка поддерживается только для объявлений 'member'. См. Другие вопросы SO о перегрузке в F #. http://stackoverflow.com/questions/2260939/f-overloading-functions –

+0

В этом случае мне нужно будет использовать тип, так как я сильно зависеть от способности перегружать методы, вы можете себе представить, что should.contain (фактические, ожидаемые) должны выполняться по-разному для строк, чем для последовательностей, например. Возможно ли перегрузить статические элементы? Очевидно, что если бы я сделал статический класс Assertion и его членов, он не продемонстрировал бы никаких методов .ToString() .... –

3

Я не думаю, что есть какой-нибудь способ сделать это в F # в целом. В частном случае .Equals и .GetHashCode вы можете сделать их непригодными для использования, поместив для вашего типа атрибут [<NoEquality>], но на самом деле этот эффект имеет семантический эффект и скрывает эти методы.

EDIT

Он также может быть стоит отметить, что беглые интерфейсы редко используются в 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 

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

+0

Спасибо, мне также пришлось поместить атрибут [], который я сделал. В этом случае затрагиваемая семантика не имеет значения. Еще нужно скрыть ToString() и GetType(), но он выглядит намного чище. –

+1

@ «Свободные интерфейсы редко используются в F #» Извините, это имя может ввести в заблуждение, моя единственная цель для этого интерфейса - скрыть вышеупомянутые методы. Я просто случайно использовал этот интерфейс для создания свободных интерфейсов на C#. –

5

Повторяя мой ответ от

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

В F # вы можете запретить Равно & GetHashCode (и удалить их из IntelliSense) путем аннотирования типа с NoEquality и атрибуты NoComparison, как показано ниже. Пользовательские методы также могут быть скрыты из списка intellisense через атрибут Obsolete или атрибут CompilerMessage с IsHidden = true. Невозможно скрыть методы System.Object GetType и ToString из F # intellisense.

[<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 
+0

Спасибо, Брайан Я применил это изменение, чтобы немного почистить его. Как я вижу, вы нашли оба места, я задал вопрос (я рассказываю свои базы). Прямо сейчас я собираюсь рассмотреть подход Томаса, поскольку он прав, что мне не нужно использовать типы, модули будут делать. –

Смежные вопросы