2008-08-20 30 views
28

Trong C#, khi bạn triển khai giao diện, tất cả thành viên đều được công khai theo mặc định. Bạn có nghĩ rằng nó tốt hơn nếu chúng ta có thể chỉ định công cụ sửa đổi khả năng truy cập (được bảo vệ, nội bộ, ngoại trừ riêng tư) hoặc tốt hơn sử dụng một lớp trừu tượng thay thế?Không phải thành viên công cộng cho giao diện C#

+8

Bạn có thể ẩn giao diện khỏi API nếu bạn triển khai nó một cách rõ ràng. – epitka

Trả lời

5

Sẽ không có ý nghĩa. Giao diện là hợp đồng với công khai mà bạn hỗ trợ các phương pháp và thuộc tính đó. Gắn bó với các lớp trừu tượng.

+6

Công cụ sửa đổi truy cập 'nội bộ' có vẻ là một điều hoàn toàn hữu ích cho các giao diện có; một giao diện có trình sửa đổi như vậy trên bất kỳ thành viên nào của nó chỉ có thể được thực hiện bằng mã trong assembly trong đó nó được khai báo, nhưng có thể được sử dụng bởi mã ở bất kỳ đâu. Tôi có thể thấy rất nhiều công dụng cho điều đó. – supercat

+1

Tôi không nghĩ rằng các giao diện có nghĩa là được sử dụng như các nguyên tắc đánh máy mạnh mẽ hoặc giàn giáo cho mã trong cùng một hội đồng. Tôi tin rằng mục đích chính của họ là "giao tiếp" với thế giới bên ngoài. – Ishmaeel

+0

Giả sử một assembly xác định BankCheckingAccount, CreditUnionCheckingAccount, BankSavingsAccount và CreditUnionSavingsAccount. Tài khoản ngân hàng có các tính năng thiếu tài khoản công đoàn tín dụng và ngược lại. Kiểm tra tài khoản có các tính năng thiếu tài khoản tiết kiệm và ngược lại. Sẽ rất hữu ích khi có các loại để kiểm tra tài khoản, tài khoản tiết kiệm, tài khoản ngân hàng và tài khoản công đoàn tín dụng, nhưng người ta chỉ có thể sử dụng các lớp trừu tượng cho hai trong số bốn tài khoản đó. Nếu thừa kế của các lớp trừu tượng được giới hạn trong cùng một assembly ... – supercat

1

Giao diện không có công cụ sửa đổi truy cập trong phương thức của chúng, để chúng mở cho bất kỳ công cụ sửa đổi truy cập nào là thích hợp. Điều này có một mục đích: nó cho phép các loại khác suy ra phương thức và thuộc tính nào có sẵn cho một đối tượng theo một giao diện. Cung cấp cho họ bảo vệ/truy cập nội bộ đánh bại mục đích của một giao diện.

Nếu bạn kiên quyết rằng bạn cần cung cấp công cụ sửa đổi truy cập cho một phương pháp, hãy để nó ra khỏi giao diện hoặc như bạn đã nói, hãy sử dụng lớp trừu tượng.

+0

cho phép các loại khác (đọc bên ngoài) suy ra phương pháp và thuộc tính nào có sẵn cho một đối tượng là lựa chọn chào mừng? Tôi sẽ nói rằng đối tượng sẽ có thể quyết định những gì nên có sẵn cho thế giới bên ngoài để suy ra. – nawfal

+0

Chính xác, nawfal - và một giao diện là một hợp đồng, không phải là một đối tượng. Giao diện nên được sử dụng để mô tả hành vi có sẵn như trái ngược với định nghĩa của một chi tiết thực hiện. –

+0

Jon, hôm nay tôi nhận ra một hợp đồng của nó. Không chỉ là một hợp đồng, nhưng giống như một "đặc điểm kỹ thuật công cộng cho toàn thế giới". Tôi đã đặt câu hỏi về nguyên tắc này, nhưng khi ppl đặt vào các từ, chúng nghe như "tại sao các thành viên giao diện lại công khai?" mà thường tìm thấy câu trả lời là hương vị của "hợp đồng của loại đó". [@Jon Skeet nói ở đây] (http://stackoverflow.com/a/11162397/661933) rằng nó là như vậy, 'coz nó là như vậy.[Ở đây] (http://stackoverflow.com/a/7238707/661933) là một hàm ý khác của việc có các thành viên giao diện không công khai. – nawfal

0

Tôi quen thuộc với Java chứ không phải C#, nhưng tại sao bạn muốn một thành viên riêng trong một giao diện? Nó không thể có bất kỳ việc thực hiện nào và sẽ vô hình đối với các lớp thực hiện, vì vậy sẽ vô dụng. Giao diện tồn tại để xác định hành vi. Nếu bạn cần hành vi mặc định hơn là sử dụng một lớp trừu tượng.

+1

một thành viên nội bộ có ý nghĩa đúng không? – nawfal

+0

Tôi nghĩ rằng có thể khai báo toàn bộ giao diện (trái ngược với một phương thức riêng) bên trong. Điều đó có ý nghĩa hơn. –

+1

@JonLimjap nó là có thể, và tốt duy nhất nó là, nó ẩn giao diện từ hội đồng bên ngoài như mong đợi, nhưng họ vẫn yêu cầu các thành viên của nó được công khai (đó là lạ) có nghĩa là những tài sản công cộng và phương pháp có thể nhìn thấy thế giới bên ngoài !! – nawfal

31

Nếu giao diện ở bên trong, tất cả các thành viên của nó sẽ nằm trong bộ phận lắp ráp. Nếu một giao diện lồng nhau được bảo vệ, chỉ có các lớp con của lớp bên ngoài mới có thể truy cập vào giao diện đó.

Các thành viên nội bộ cho một giao diện bên ngoài tổ hợp khai báo của nó sẽ là vô nghĩa, như các thành viên được bảo vệ cho một giao diện bên ngoài lớp khai báo ngoài của nó.

Điểm của giao diện là mô tả hợp đồng giữa loại triển khai và người dùng giao diện. Người gọi bên ngoài sẽ không quan tâm và không nên để quan tâm đến việc triển khai, đó là những gì các thành viên nội bộ và được bảo vệ.

Đối với các thành viên được bảo vệ được gọi bởi một lớp cơ sở, các lớp trừu tượng là cách để xác định hợp đồng giữa các lớp cơ sở và các lớp thừa hưởng từ chúng. Nhưng trong trường hợp này, chi tiết triển khai thường rất phù hợp, trừ khi đó là lớp trừu tượng thuần khiết thoái hóa (trong đó tất cả các thành viên đều trừu tượng), trong trường hợp thành viên được bảo vệ là vô ích. Trong trường hợp đó, hãy đi với một giao diện và lưu lớp cơ sở duy nhất để triển khai các kiểu để chọn.

+0

ý của bạn là gì đối với "người dùng giao diện đó"? Vì vậy, khi bạn tạo một biến cho phép nói IMyInterface someVar; Và sau đó sử dụng someVar bằng cách nào đó? – PositiveGuy

+0

Ngoài ra tôi có thể thêm rằng giao diện buộc một mô hình/phổ biến cho cấu trúc của ứng dụng của bạn (các lớp bên trong) mà là một điểm ôm ngay cả khi bạn không lộ các giao diện cho khách hàng bên ngoài ... phải không ?? – PositiveGuy

+0

@coffeeaddict có và có. –

20

Bạn có thể ẩn thực hiện một giao diện bằng cách nói rõ ràng tên giao diện trước tên phương pháp:

public interface IInterface { 
    public void Method(); 
} 

public class A : IInterface { 
    public void IInterface.Method() { 
     // Do something 
    } 
} 

public class Program { 
    public static void Main() { 
     A o = new A(); 
     o.Method(); // Will not compile 
     ((IInterface)o).Method(); // Will compile 
    } 
} 
+1

Chỉ cần một bình luận: ngày nay bạn không thể sử dụng công cụ sửa đổi 'public' trong một thành viên giao diện hoặc một phương thức giao diện được thực hiện một cách rõ ràng. Ví dụ, mã của bạn làm việc với .NET 4.5, chỉ cần xóa cả hai 'public'. – Andrew

+0

Andrew, bạn có ý nghĩa gì với hai công chúng? –

+0

Tại sao không phải 'o.Method()' biên dịch? Ai đó có thể giải thích điều này? Tại sao nêu tên giao diện ẩn thực hiện giao diện? –

2

Một giao diện là một hợp đồng mà tất cả các lớp thực hiện tuân thủ. Điều này có nghĩa là họ phải tuân theo tất cả hoặc không ai trong số đó.

Nếu giao diện được công khai thì mọi phần của liên hệ đó phải được công khai, nếu không nó sẽ có nghĩa là một người bạn/lớp nội bộ và một thứ khác với mọi thứ khác.

Hoặc sử dụng lớp cơ sở trừu tượng hoặc (nếu có thể và thực tế) là internal extension method on the interface.

+0

Nếu một người khai báo lớp trừu tượng công khai, tất cả các thành viên và nhà xây dựng của họ là 'nội bộ', thì mã bên ngoài có thể nhận được từ tham chiếu assembly đến những thứ thuộc loại đó và chuyển các tham chiếu đó trở lại phương thức của assembly. an toàn trong suốt, mà không có mã bên ngoài phải biết bất cứ điều gì về lớp học được đề cập. Thật không may, cách tiếp cận như vậy sẽ chỉ hoạt động nếu không có các dẫn xuất cụ thể nào của lớp trừu tượng sẽ cần phải kế thừa từ bất cứ thứ gì không lấy được từ lớp trừu tượng đó. – supercat

+0

Một giao diện chứa các thành viên nội bộ, nếu một điều như vậy được cho phép, sẽ giống như lớp trừu tượng nói trên, nhưng với lợi thế là nó có thể được thực hiện bởi các lớp được bắt nguồn từ các lớp không có. – supercat

2

Bạn có thể ẩn gần như tất cả mã được triển khai bằng giao diện cho các hội đồng bên ngoài.

interface IVehicle 
{ 
    void Drive(); 
    void Steer(); 
    void UseHook(); 
} 
abstract class Vehicle // :IVehicle // Try it and see! 
{ 
    /// <summary> 
    /// Consuming classes are not required to implement this method. 
    /// </summary> 
    protected virtual void Hook() 
    { 
     return; 
    } 
} 
class Car : Vehicle, IVehicle 
{ 
    protected override void Hook() // you must use keyword "override" 
    { 
     Console.WriteLine(" Car.Hook(): Uses abstracted method."); 
    } 
    #region IVehicle Members 

    public void Drive() 
    { 
     Console.WriteLine(" Car.Drive(): Uses a tires and a motor."); 
    } 

    public void Steer() 
    { 
     Console.WriteLine(" Car.Steer(): Uses a steering wheel."); 
    } 
    /// <summary> 
    /// This code is duplicated in implementing classes. Hmm. 
    /// </summary> 
    void IVehicle.UseHook() 
    { 
     this.Hook(); 
    } 

    #endregion 
} 
class Airplane : Vehicle, IVehicle 
{ 
    protected override void Hook() // you must use keyword "override" 
    { 
     Console.WriteLine(" Airplane.Hook(): Uses abstracted method."); 
    } 
    #region IVehicle Members 

    public void Drive() 
    { 
     Console.WriteLine(" Airplane.Drive(): Uses wings and a motor."); 
    } 

    public void Steer() 
    { 
     Console.WriteLine(" Airplane.Steer(): Uses a control stick."); 
    } 
    /// <summary> 
    /// This code is duplicated in implementing classes. Hmm. 
    /// </summary> 
    void IVehicle.UseHook() 
    { 
     this.Hook(); 
    } 

    #endregion 
} 

Điều này sẽ kiểm tra mã.

class Program 
{ 
    static void Main(string[] args) 
    { 
     Car car = new Car(); 
     IVehicle contract = (IVehicle)car; 
     UseContract(contract); // This line is identical... 
     Airplane airplane = new Airplane(); 
     contract = (IVehicle)airplane; 
     UseContract(contract); // ...to the line above! 
    } 

    private static void UseContract(IVehicle contract) 
    { 
     // Try typing these 3 lines yourself, watch IDE behavior. 
     contract.Drive(); 
     contract.Steer(); 
     contract.UseHook(); 
     Console.WriteLine("Press any key to continue..."); 
     Console.ReadLine(); 
    } 
} 
2

Tất cả câu trả lời ở đây nhiều hay ít nói đó là cách giao diện có nghĩa là, chúng là thông số chung của công chúng.

Đây là chuỗi được thảo luận nhiều nhất, hãy để tôi đăng hai câu trả lời tuyệt vời mà tôi tìm thấy trên SO khi câu hỏi này nổi lên trong tâm trí của tôi.

This answer gives an example cách không thể vô nghĩa để có các bộ định danh truy cập không đồng đều cho các thành viên giao diện trong các lớp dẫn xuất. Mã luôn tốt hơn mô tả kỹ thuật.

Đối với tôi, điều gây hại nhất về các thành viên giao diện công cộng bắt buộc là giao diện có thể là nội bộ trong hội đồng nhưng các thành viên mà nó phơi bày phải công khai. Jon Skeet explains here that's by design sadly.

Điều đó đặt ra câu hỏi tại sao các giao diện không được thiết kế để có định nghĩa không công khai cho các thành viên. Điều đó có thể làm cho hợp đồng linh hoạt. Điều này là khá hữu ích khi viết hội đồng nơi bạn không muốn các thành viên cụ thể của các lớp học được tiếp xúc với bên ngoài lắp ráp. Tôi không biết tại sao.

0

Trong ý kiến ​​của tôi, điều này vi phạm đóng gói. Tôi phải thực hiện một methos là công cộng sau đó tôi thực hiện một giao diện. Tôi thấy không có lý do gì để ép buộc công chúng trong một lớp học ngụ ý giao diện. (C#)

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