2008-08-20 9 views
28

In C# sind bei der Implementierung einer Schnittstelle standardmäßig alle Mitglieder öffentlich. Denkst du, es ist besser, wenn wir den Accessibility-Modifier angeben können (geschützt, intern, außer privat natürlich) oder lieber eine abstrakte Klasse verwenden?Nicht öffentliche Mitglieder für C# -Schnittstellen

+8

Sie können die Schnittstelle von der API ausblenden, wenn Sie sie explizit implementieren. – epitka

Antwort

5

Würde keinen Sinn ergeben. Eine Schnittstelle ist ein Vertrag mit der öffentlichen, die Sie diese Methoden und Eigenschaften unterstützen. Bleib bei abstrakten Klassen.

+6

Ein "interner" Zugriffsmodifikator scheint für Schnittstellen eine durchaus nützliche Sache zu sein; eine Schnittstelle, die einen solchen Modifizierer auf irgendeinem ihrer Mitglieder hat, könnte nur durch Code in der Assembly implementiert werden, in dem sie deklariert ist, könnte aber überall von Code verwendet werden. Ich kann viel Nutzen dafür sehen. – supercat

+1

Ich denke nicht, dass Schnittstellen als stark typisierte Richtlinien oder als Gerüst für Code innerhalb derselben Baugruppen verwendet werden sollen. Ich glaube, ihr Hauptzweck ist es, sich mit der Außenwelt zu verbinden. – Ishmaeel

+0

Angenommen, eine Assembly definiert BankCheckingAccount, CreditUnionCheckingAccount, BankSavingsAccount und CreditUnionSavingsAccount. Bankkonten weisen Merkmale auf, die in den Konten der Konten der Konten fehlen und umgekehrt. Girokonten haben Funktionen, die in Sparkonten fehlen und umgekehrt. Es wäre hilfreich, Typen für Girokonten, Sparkonten, Bankkonten und Genossenschaftskonten zu haben, aber für zwei dieser vier könnte man nur abstrakte Klassen verwenden. Wenn die Vererbung der abstrakten Klassen auf dieselbe Baugruppe beschränkt wäre ... – supercat

1

Schnittstellen verfügen in ihren Methoden nicht über Zugriffsmodifikatoren, sodass sie für den Zugriffsmodifikator offen bleiben. Dies hat einen Zweck: Es ermöglicht anderen Typen, zu ermitteln, welche Methoden und Eigenschaften für ein Objekt, das einer Schnittstelle folgt, verfügbar sind. Wenn Sie geschützte/interne Zugriffe erhalten, wird der Zweck einer Schnittstelle vereitelt.

Wenn Sie darauf bestehen, dass Sie einen Zugriffsmodifizierer für eine Methode bereitstellen müssen, lassen Sie sie entweder aus der Schnittstelle heraus oder verwenden Sie wie erwähnt eine abstrakte Klasse.

+0

anderen (lesen externen) Typen zu entnehmen, welche Methode und Eigenschaften für ein Objekt verfügbar sind, ist eine willkommene Wahl? Ich würde sagen, dass das Objekt in der Lage sein sollte zu entscheiden, was für die Außenwelt verfügbar sein sollte. – nawfal

+0

Genau, nawfal - und eine Schnittstelle ist ein Vertrag, kein Objekt. Schnittstellen sollten verwendet werden, um verfügbares Verhalten im Gegensatz zur Definition eines Implementierungsdetails zu beschreiben. –

+0

Jon, heute habe ich realisiert, dass es ein Vertrag ist. Nicht nur ein Vertrag, sondern eher eine "öffentliche Spezifikation für die ganze Welt". Ich habe dieses Prinzip in Frage gestellt, aber wenn es in Worte gefasst wird, klingen sie wie "Warum sind Interface-Mitglieder öffentlich?" für die oft gefundene Antworten sind Aromen von "es ist ein Vertrag dieser Art". [@ Jon Skeet sagt hier] (http://stackoverflow.com/a/11162397/661933), dass es so ist, 'coz ist es so.[Here] (http://stackoverflow.com/a/7238707/661933) ist eine weitere Implikation von nichtöffentlichen Interface-Mitgliedern. – nawfal

0

Ich bin vertraut mit Java und nicht C#, aber warum eine Erde möchten Sie ein privates Mitglied in einer Schnittstelle? Es könnte keine Implementierung haben und wäre unsichtbar für die Implementierung von Klassen, wäre also nutzlos. Schnittstellen existieren, um Verhalten zu spezifizieren. Wenn Sie Standardverhalten benötigen, verwenden Sie eine abstrakte Klasse.

+1

ein internes Mitglied macht Sinn, oder? – nawfal

+0

Ich denke, es ist möglich, eine ganze Schnittstelle (im Gegensatz zu einer individuellen Methode) intern zu deklarieren. Das macht mehr Sinn. –

+1

@ JonLimjap ist es möglich, und das einzige Gute ist, es verbirgt die Schnittstelle von externen Baugruppen wie erwartet, aber sie erfordert immer noch seine Mitglieder öffentlich (was seltsam ist) was bedeutet, dass diese öffentlichen Eigenschaften und Methoden für die Außenwelt sichtbar sind !! – nawfal

31

Wenn eine Schnittstelle intern ist, sind alle ihre Mitglieder intern in der Baugruppe. Wenn eine verschachtelte Schnittstelle geschützt ist, können nur die Unterklassen der äußeren Klasse auf diese Schnittstelle zugreifen.

Interne Member für eine Schnittstelle außerhalb ihrer deklarierenden Assembly wären sinnlos, ebenso wie geschützte Member für eine Schnittstelle außerhalb ihrer deklarierenden äußeren Klasse.

Der Punkt einer Schnittstelle ist die Beschreibung eines Vertrags zwischen einem Implementierungstyp und den Benutzern der Schnittstelle. Externe Anrufer werden sich nicht darum kümmern und sollten nicht haben, um sich um die Implementierung zu kümmern, wofür interne und geschützte Mitglieder sind.

Für geschützte Member, die von einer Basisklasse aufgerufen werden, sind abstrakte Klassen der Weg zur Angabe eines Vertrags zwischen Basisklassen und Klassen, die von ihnen erben. Aber in diesem Fall sind Implementierungsdetails in der Regel sehr relevant, es sei denn, es handelt sich um eine entartete reine abstrakte Klasse (wobei alle Mitglieder sind abstrakt) in diesem Fall geschützte Mitglieder sind nutzlos. In diesem Fall sollten Sie mit einer Schnittstelle arbeiten und die einzelne Basisklasse für die Implementierung von Typen zur Auswahl speichern.

+0

Was meinen Sie mit "Benutzer dieser Schnittstelle"? Also, wenn Sie eine Variable erstellen, sagen wir mal IMyInterface someVar; Und dann irgendwie mitVar? – PositiveGuy

+0

Auch ich kann hinzufügen, dass Interfaces ein Muster/Gemeinsamkeit auf die Struktur Ihrer Anwendung (die Klassen innerhalb) zwingen, die ein Umarmungspunkt ist, auch wenn Sie nicht die Schnittstellen zu externen Clients offen legen ... richtig? – PositiveGuy

+0

@coffeeaddict ja und ja. –

20

Sie können die Implementierung einer Schnittstelle ausblenden, indem Sie den Namen der Schnittstelle vor dem Methodennamen explizit besagt:

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

Nur ein Kommentar: Heutzutage können Sie den Modifikator 'public' in einem Interface-Member oder einer explizit implementierten Interface-Methode nicht verwenden. Damit Ihr Code beispielsweise mit .NET 4.5 funktioniert, sollten einfach beide 'public's entfernt werden. – Andrew

+0

Andrew, welche zwei Öffentlichkeiten meinst du? –

+0

Warum sollte 'o.Method()' nicht kompiliert werden? Kann jemand das erklären? Warum verbirgt die Angabe des Schnittstellennamens die Implementierung der Schnittstelle? –

2

Eine Schnittstelle ist ein Vertrag, der alle implementierenden Klassen zu halten. Dies bedeutet, dass sie sich an alles oder nichts davon halten müssen.

Wenn die Schnittstelle öffentlich ist, dann muss jeder Teil dieses Kontakts öffentlich sein, sonst würde es einen Freund/interne Klassen und eine andere Sache zu allem anderen bedeuten. Verwenden Sie eine abstrakte Basisklasse oder (wenn möglich und praktisch) eine internal extension method on the interface.

+0

Wenn eine öffentliche abstrakte Klasse deklariert würde, deren Mitglieder und Konstruktoren "internal" wären, könnte externer Code von der Assembly Verweise auf Dinge dieses Typs erhalten und diese Verweise an die Methoden der Assembly zurückgeben, während der Typ beibehalten wird Sicherheit überall, ohne dass der äußere Code etwas über die betreffende Klasse wissen muss. Leider würde ein solcher Ansatz nur funktionieren, wenn keine der konkreten Ableitungen der abstrakten Klasse von irgendetwas erben müsste, das nicht von dieser abstrakten Klasse abgeleitet ist. – supercat

+0

Eine Schnittstelle, die interne Member enthielt, würde, wenn eine solche Sache erlaubt wäre, der oben erwähnten abstrakten Klasse sehr ähnlich sein, aber mit dem Vorteil, dass sie durch Klassen implementiert werden könnte, die von Klassen abgeleitet wurden, die dies nicht taten. – supercat

2

Sie können fast den gesamten Code ausblenden, der von Schnittstellen zu externen Baugruppen implementiert wird.

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 
} 

Dies wird den Code testen.

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

Alle Antworten hier mehr oder weniger sagen, das ist, wie Schnittstellen sein sollen, sie sind universelle öffentliche Spezifikationen.

Dies ist der meistdiskutierte Thread, lassen Sie mich zwei ausgezeichnete Antworten, die ich auf SO gefunden habe, wenn diese Frage tauchte meine Meinung.

This answer gives an example wie es unsinnig sein kann, nicht einheitliche Zugriffsspezifizierer für Schnittstellenelemente in abgeleiteten Klassen zu haben. Code immer besser als technische Beschreibungen.

Für mich am meisten verdammte Sache über erzwungene öffentliche Schnittstellenmitglieder sind, dass die Schnittstelle selbst innerhalb einer Versammlung sein kann, aber die Mitglieder, die sie ausstellt, müssen öffentlich sein. Jon Skeet explains here that's by design sadly.

Das wirft die Frage auf, warum nicht Schnittstellen entwickelt wurden, nicht-öffentliche Definitionen für Mitglieder zu haben. Das kann den Vertrag flexibel machen. Dies ist sehr nützlich beim Schreiben von Assemblys, bei denen bestimmte Member von Klassen nicht außerhalb der Assembly angezeigt werden sollen. Keine Ahnung warum.

0

Meiner Meinung nach verstößt dies gegen Kapselung. Ich muss ein methos als public implementieren, dann implementiere ich eine Schnittstelle. Ich sehe keinen Grund, die Öffentlichkeit in einer Klasse zu zwingen, die die Schnittstelle implementiert. (C#)