2010-03-05 37 views
5

Tôi hiện đang triển khai một khuôn khổ Spec trong F # và tôi muốn ẩn các phương thức Equals, GetHashCode vv trên loại should của mình, để API không bị lộn xộn với các loại này.Làm cách nào để ẩn các phương thức trong F #?

Tôi biết trong C# nó được thực hiện bằng cách làm cho lớp thực hiện một giao diện như thế này:

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

tôi đã cố gắng làm điều tương tự trong 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 

thực hiện nó trong loại của tôi:

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

nhưng không thành công.

Tôi cũng đã cố gắng ghi đè các phương thức trong loại của tôi và thêm thuộc tính theo cách đó, nhưng điều đó cũng không thực hiện được.

Vì vậy, câu hỏi vẫn còn, làm cách nào tôi có thể xóa API của mình?

Edit:

Nhờ sự giúp đỡ (xem dưới đây) tôi đã có thể giải quyết vấn đề của tôi.

Tóm lại, .Equals.GetHashCode có thể bị ẩn qua [<NoEquality>][<NoComparison>] nhưng điều đó cũng sẽ thay đổi ngữ nghĩa.

Ẩn thông qua thuộc tính EditorBrowsable không hoạt động.

Cách duy nhất để có API sạch và vẫn có khả năng quá tải phương pháp là làm cho các thành viên phương pháp này tĩnh.

Lớp kết quả có thể được tìm thấy bằng cách duyệt bên trong dự án của tôi FSharpSpec.

Loại trong câu hỏi có thể được tìm thấy here.

Nhờ mọi người giúp tôi giải quyết vấn đề này.

Chúc mừng ...

Trả lời

4

Hoặc, bạn có thể thiết kế thư viện bằng cách sử dụng kiểu thay thế bằng các hàm được đính kèm trong mô-đun. Đây là cách thông thường để viết chức năng mã trong F # và sau đó bạn sẽ không cần phải ẩn bất kỳ phương thức .NET chuẩn nào. Để hoàn thành ví dụ đưa ra bởi 'kvb', đây là một ví dụ về giải pháp hướng đối tượng:

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 

Cách chức năng của văn bản mã có thể trông như thế này:

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 

Nếu bạn gõ MyNum. , F # IntelliSense sẽ hiển thị các chức năng được xác định trong mô-đun, vì vậy bạn sẽ không thấy bất kỳ nhiễu nào trong trường hợp này.

+0

Tôi sẽ xem xét điều đó, tôi giả định cách tiếp cận này cũng sẽ cho phép tôi quá tải các phương pháp? - Một lưu ý khác, tôi rất thích màn hình của bạn trên F #. –

+0

Cảm ơn! Thật không may, các hàm được khai báo bằng cách sử dụng 'let' không thể bị quá tải. Quá tải chỉ được hỗ trợ cho các khai báo 'member'. Xem các câu hỏi SO khác về quá tải trong F # - ví dụ: http://stackoverflow.com/questions/2260939/f-overloading-functions –

+0

Trong trường hợp đó, tôi cần phải sử dụng một loại, vì tôi phụ thuộc rất nhiều vào khả năng quá tải phương pháp, bạn có thể tưởng tượng rằng một should.contain (thực tế, dự kiến) cần phải được thực hiện khác nhau cho chuỗi hơn cho chuỗi ví dụ. Có thể quá tải thành viên tĩnh không? Rõ ràng, nếu tôi sẽ làm cho lớp Assertion của tôi và các thành viên của nó tĩnh, nó sẽ không hiển thị bất kỳ phương thức .ToString() ... nào. –

3

Tôi không nghĩ rằng có cách nào để làm điều đó trong F # nói chung. Trong trường hợp cụ thể là .Equals.GetHashCode, bạn có thể làm cho chúng không sử dụng được bằng cách đặt thuộc tính [<NoEquality>] vào loại của bạn, nhưng điều này thực sự có tác dụng ngữ nghĩa ngoài việc ẩn các phương thức đó.

EDIT

Nó cũng có thể là đáng nói đến là giao diện thông thạo ít khi được sử dụng trong F #, vì nó nhiều hơn nữa thành ngữ sử dụng combinators và pipelining để thay thế. Ví dụ, hãy tưởng tượng rằng chúng ta muốn tạo một cách để tạo ra các biểu thức số học.Thay vì

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

Tôi nghĩ rằng hầu hết # người dùng F muốn viết

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

Với phong cách này, không cần phải che giấu các thành viên vì biểu thức được đường ống để combinators, thay vì gọi phương pháp của một biểu thức người xây dựng.

+0

Cảm ơn, tôi cũng phải đặt thuộc tính [], mà tôi đã làm. Các ngữ nghĩa bị ảnh hưởng không quan trọng trong trường hợp này. Vẫn cần ẩn ToString() và GetType() nhưng có vẻ đã sạch hơn nhiều. –

+1

@ "Giao diện thông thạo hiếm khi được sử dụng trong F #" Tôi xin lỗi, tên có thể gây hiểu lầm, mục đích duy nhất của tôi cho giao diện này là ẩn các phương pháp được đề cập ở trên. Tôi chỉ sử dụng loại giao diện này rất nhiều để tạo giao diện thông thạo trong C#. –

5

Lặp đi lặp lại câu trả lời của tôi từ

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

Trong F # bạn có thể không cho phép bằng & GetHashCode (và loại bỏ chúng khỏi IntelliSense) bằng cách chú thích loại với NoEquality và NoComparison thuộc tính, như hình dưới đây. Các phương thức do người dùng định nghĩa cũng có thể được ẩn khỏi danh sách intellisense thông qua thuộc tính Obsolete hoặc thuộc tính CompilerMessage với IsHidden = true. Không có cách nào để ẩn các phương thức System.Object GetType và ToString khỏi 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

Cảm ơn, Brian Tôi đã áp dụng thay đổi này để làm sạch phần nào. Như tôi có thể thấy bạn tìm thấy cả hai nơi đã được tôi hỏi câu hỏi (tôi bao gồm các căn cứ của tôi). Ngay bây giờ tôi sẽ xem xét cách tiếp cận Tomas, vì anh ấy đúng, rằng tôi không cần phải sử dụng các loại, mô-đun sẽ làm. –

Các vấn đề liên quan