Membri non pubblici per interfacce C #

In C #, quando si implementa un’interfaccia, tutti i membri sono implicitamente pubblici. Non sarebbe meglio se potessimo specificare il modificatore di accessibilità ( protected , internal , tranne private ovviamente), o dovremmo semplicemente usare una class astratta invece?

Se un’interfaccia è interna, tutti i suoi membri saranno interni all’assembly. Se un’interfaccia annidata è protetta, solo le sottoclassi della class esterna potrebbero accedere a tale interfaccia.

I membri interni per un’interfaccia esterna all’assembly dichiarante non sarebbero utili, così come i membri protetti per un’interfaccia esterna alla class esterna dichiarante.

Il punto di un’interfaccia è descrivere un contratto tra un tipo di implementazione e gli utenti dell’interfaccia. I chiamanti esterni non si prenderanno cura di loro e non dovrebbero preoccuparsi dell’implementazione, che è ciò per cui sono membri interni e protetti.

Per i membri protetti che sono chiamati da una class base, le classi astratte sono la strada da seguire per specificare un contratto tra classi base e classi che ereditano da esse. Ma in questo caso, i dettagli di implementazione sono in genere molto rilevanti, a meno che non si tratti di una class astratta astratta degenerata (in cui tutti i membri sono astratti), nel qual caso i membri protetti sono inutili. In tal caso, vai con un’interfaccia e salva la singola class base per implementare i tipi da scegliere.

È ansible hide l’implementazione di un’interfaccia dichiarando esplicitamente il nome dell’interfaccia prima del nome del metodo:

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

Non avrebbe senso. Un’interfaccia è un contratto con il pubblico che supporti tali metodi e proprietà. Segui lezioni astratte.

Tutte le risposte qui dicono più o meno come sono le interfacce, sono specifiche pubbliche universali.

Essendo il thread più discusso, lasciatemi pubblicare due ottime risposte che ho trovato su SO quando questa domanda è emersa nella mia mente.

Questa risposta fornisce un esempio di come può essere insensato avere identificatori di accesso non uniformi per i membri dell’interfaccia nelle classi derivate. Il codice è sempre migliore delle descrizioni tecniche.

Per me la cosa più schiacciante dei membri di un’interfaccia pubblica forzata è che l’interfaccia stessa può essere interna a un assembly, ma i membri che espone devono essere pubblici. Jon Skeet spiega qui che è di progettazione tristemente .

Ciò solleva la questione del perché le interfacce non fossero progettate per avere definizioni non pubbliche per i membri. Questo può rendere il contratto flessibile. Questo è piuttosto utile quando si scrivono assiemi in cui non si desidera che membri specifici delle classi vengano esposti all’esterno dell’assieme. Non so perché.

Un’interfaccia è un contratto a cui tutte le classi di implementazione aderiscono. Ciò significa che devono aderire a tutto ciò o a nessuno di essi.

Se l’interfaccia è pubblica allora ogni parte di quel contatto deve essere pubblica, altrimenti significherebbe una per amico / classi interne e una cosa diversa per tutto il resto.

Utilizzare una class base astratta o (se ansible e pratico) un metodo di estensione interno sull’interfaccia .

È ansible hide quasi tutto il codice implementato dalle interfacce agli assembly esterni.

 interface IVehicle { void Drive(); void Steer(); void UseHook(); } abstract class Vehicle // :IVehicle // Try it and see! { ///  /// Consuming classs are not required to implement this method. ///  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."); } ///  /// This code is duplicated in implementing classs. Hmm. ///  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."); } ///  /// This code is duplicated in implementing classs. Hmm. ///  void IVehicle.UseHook() { this.Hook(); } #endregion } 

Questo testerà il codice.

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

Le interfacce non hanno modificatori di accesso nei loro metodi, lasciandoli aperti a qualsiasi modificatore di accesso appropriato. Questo ha uno scopo: consente ad altri tipi di dedurre quali metodi e proprietà sono disponibili per un object che segue un’interfaccia. Fornendole accessorie protette / interne sconfigge lo scopo di un’interfaccia.

Se sei irremovibile sul fatto che devi fornire un modificatore di accesso per un metodo, o lasciarlo fuori dall’interfaccia, o come hai detto, usa una class astratta.

Conosco Java piuttosto che C #, ma perché una terra vorresti un membro privato all’interno di un’interfaccia? Non potrebbe avere alcuna implementazione e sarebbe invisibile all’implementazione delle classi, quindi sarebbe inutile. Esistono interfacce per specificare il comportamento. Se hai bisogno di un comportamento predefinito piuttosto che usare una class astratta.

Nella mia opinione questo viola l’incapsulamento. Devo implementare un methos come pubblico, quindi implemento un’interfaccia. Non vedo alcun motivo per forzare il pubblico in una class che impone l’interfaccia. (C #)