2010-03-05 11 views
5

Actualmente estoy implementando un framework Spec en F # y quiero ocultar los métodos Equals, GetHashCode etc. en mi tipo should, para que la API no esté saturada con estos.¿Cómo puedo ocultar los métodos en F #?

sé en C# que se realiza haciendo la clase implemente una interfaz como esta:

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(); 
} 

He intentado hacer lo mismo en C#:

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 

puesto en práctica en mi tipo:

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

pero sin éxito.

También traté de anular los métodos en mi tipo y agregar el atributo de esa manera, pero eso tampoco funcionó.

Entonces, la pregunta sigue siendo, ¿cómo puedo limpiar mi API?

Editar:

Gracias a la ayuda (véase más adelante) que fue capaz de resolver mi problema.

En resumen, .Equals y .GetHashCode se puede ocultar a través de [<NoEquality>][<NoComparison>] sino que también va a cambiar la semántica.

La ocultación mediante atributos EditorBrowsable no funciona.

La única manera de tener una API limpia y aún poder sobrecargar métodos es hacer que estos miembros de método estén estáticos.

La clase resultante se puede encontrar navegando dentro de mi proyecto FSharpSpec.

El tipo en cuestión se puede encontrar here.

Gracias a todos los que me ayudó a resolver este problema.

Saludos ...

Respuesta

4

Alternativamente, podría diseñar la biblioteca utilizando un estilo alternativo utilizando las funciones incluidas en un módulo. Esta es la forma habitual de escribir código funcional en F # y luego no necesitará ocultar ningún método .NET estándar. Para completar el ejemplo dado por 'kvb', aquí hay un ejemplo de una solución orientada a objetos:

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 

La forma funcional de la escritura del código podría tener este aspecto:

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 

Si escribe MyNum. , el F # IntelliSense mostrará las funciones definidas en el módulo, por lo que no verá ningún ruido en este caso.

+0

Voy a analizar eso, ¿supongo que este enfoque también me permitirá sobrecargar los métodos? - En otra nota, disfruté tus proyecciones de pantalla en F #. –

+0

¡Gracias! Desafortunadamente, las funciones declaradas usando 'let' no se pueden sobrecargar. La sobrecarga solo se admite para declaraciones de 'miembros'. Consulte otras preguntas sobre SO sobre sobrecarga en F # - p. http://stackoverflow.com/questions/2260939/f-overloading-functions –

+0

Bueno, en ese caso necesitaría usar un tipo, ya que dependo mucho de la capacidad de sobrecargar los métodos, se puede imaginar que debe.contain (real, esperado) debe implementarse de manera diferente para cadenas que para secuencias, por ejemplo. ¿Es posible sobrecargar los miembros estáticos? Obviamente, si quisiera que mi clase Assertion y sus miembros permanezcan estáticos, no mostraría ningún método .ToString() ... –

3

No creo que haya ninguna manera de hacerlo en Fa # en general. En el caso particular de .Equals y .GetHashCode, puede hacerlos inutilizables poniendo un atributo [<NoEquality>] en su tipo, pero esto en realidad tiene un efecto semántico además de ocultar esos métodos.

EDITAR

También podría valer la pena mencionar que las interfaces fluidas rara vez se utilizan en C#, ya que es mucho más idiomática utilizar combinadores y la canalización lugar. Por ejemplo, imagina que queremos crear una forma de crear expresiones aritméticas.En lugar de

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

creo que la mayoría de # usuarios de F preferirían escribir

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

Con este estilo, no hay necesidad de ocultar los miembros porque las expresiones consiguen hilo de combinadores, en lugar de llamar a los métodos de expresión constructor.

+0

Gracias, también tuve que poner el atributo [], lo que hice. La semántica afectada no importa en este caso. Aún necesita ocultar ToString() y GetType(), pero parece mucho más limpio. –

+1

@ "las interfaces fluidas se usan raramente en F #" Lo siento, el nombre puede ser engañoso, mi único propósito para esta interfaz es ocultar los métodos mencionados anteriormente. Simplemente uso este tipo de interfaz mucho para crear interfaces fluidas en C#. –

5

Repitiendo mi respuesta de

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

En F #, usted puede impedir es igual & GetHashCode (y eliminarlos de IntelliSense) anotando el tipo con el NoEquality y atributos NoComparison, como se muestra a continuación. Los métodos definidos por el usuario también se pueden ocultar de la lista intellisense mediante el atributo Obsoleto o el atributo CompilerMessage con IsHidden = true. No hay forma de ocultar los métodos System.Object GetType y ToString del intellisense F #.

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

Gracias, Brian Apliqué este cambio para limpiarlo un poco. Como puedo ver, encontraste los dos lugares donde hice la pregunta (cubro mis bases). En este momento voy a considerar el enfoque de Tomas, ya que es correcto, que no necesito usar tipos, los módulos sí. –

Cuestiones relacionadas