web-dev-qa-db-fra.com

Pourquoi ne puis-je pas avoir des membres d'interface protégés?

Quel est l'argument contre la déclaration des membres à accès protégé sur les interfaces? Ceci, par exemple, n'est pas valide:

public interface IOrange
{
    public OrangePeel Peel { get; }
    protected OrangePips Seeds { get; }
}

Dans cet exemple, l'interface IOrange garantirait que les développeurs au moins fournissent une instance OrangePips à leurs héritiers. Si l'implémenteur le souhaitait, il pourrait étendre la portée à public:

public class NavelOrange : IOrange
{
    public OrangePeel Peel { get { return new OrangePeel(); } }
    protected OrangePips Seeds { get { return null; } }
}

public class ValenciaOrange : IOrange
{
    public OrangePeel Peel { get { return new OrangePeel(); } }
    public OrangePips Seeds { get { return new OrangePips(6); } }
}

L’intention des membres protected sur les interfaces est de fournir un contrat de support pour héritiers (sous-classes), par exemple:

public class SpecialNavelOrange : NavelOrange
{
    ...
    // Having a seed value is useful to me.
    OrangePips seeds = this.Seeds; 
    ...
}

(Certes, cela ne fonctionnerait pas pour structs)

Je ne vois pas vraiment de cas pour les modificateurs private ou internal dans les interfaces, mais supporter les modificateurs public et protected semble parfaitement raisonnable.


Je vais essayer d'expliquer l'utilité des membres protected sur interfaces en les séparant complètement de interfaces:

Imaginons un nouveau mot clé C #, support, pour appliquer les contrats d'héritier, de manière à déclarer les éléments comme suit:

public support IOrangeSupport
{
    OrangePips Seeds { get; }
}

Cela nous permettrait de contracter des classes pour fournir des membres protégés à leurs héritiers:

public class NavelOrange : IOrange, IOrangeSupport
{
    public OrangePeel Peel { get { return new OrangePeel(); } }
    protected OrangePips Seeds { get { return null; } }
}

Ce n'est pas particulièrement utile, car les classes impliqueraient déjà ce contrat en fournissant les membres protected en premier lieu.

Mais alors nous pourrions aussi faire ceci:

public interface IOrange : IOrangeSupport
{
   ...
}

En appliquant IOrangeSupport à toutes les classes qui implémentent IOrange et en leur demandant de fournir des membres protected particuliers - ce que nous ne pouvons pas faire actuellement.

62
ajlane

Je pense que tout le monde a martelé le point d'une interface n'ayant que des membres du public, pas de détails de mise en œuvre. Ce que vous recherchez est un classe abstraite

public interface IOrange
{
    OrangePeel Peel { get; }
}

public abstract class OrangeBase : IOrange
{
    protected OrangeBase() {}
    protected abstract OrangePips Seeds { get; }
    public abstract OrangePeel Peel { get; }
}

public class NavelOrange : OrangeBase
{
    public override OrangePeel Peel { get { return new OrangePeel(); } }
    protected override OrangePips Seeds { get { return null; } }
}

public class ValenciaOrange : OrangeBase
{
    public override OrangePeel Peel { get { return new OrangePeel(); } }
    protected override OrangePips Seeds { get { return new OrangePips(6); } }
}

Edit: Il est juste de dire que si nous avons un PlasticOrange qui dérive d’une classe Ornament, il ne peut implémenter que IOrange et non la méthode protégée Seeds. C'est bon. Une interface est par définition un contrat entre un appelant et un objet, pas entre une classe et ses sous-classes. La classe abstraite est aussi proche que nous arrivons à ce concept. Et c'est bon. Ce que vous proposez essentiellement est une autre construction du langage par laquelle nous pouvons changer de sous-classe d’une classe de base à une autre sans rompre la construction. Pour moi, cela n'a pas de sens. 

Si vous créez une sous-classe d'une classe, la sous-classe est une spécialisation de la classe de base. Il doit être pleinement conscient de tout membre protégé de la classe de base. Mais si vous souhaitez changer soudainement la classe de base, il n’est pas logique que la sous-classe fonctionne avec un autre IOrange.

Je suppose que vous avez une bonne question, mais cela semble être un cas d'espoir et je ne vois aucun avantage à ce que cela soit honnête.

55
Szymon Rozga

Je ne vois pas pourquoi on voudrait cela. Si vous voulez que la classe dérivée fournisse une implémentation d'une méthode particulière, optez pour les classes de base abstraites. Les interfaces ne sont que cela - des interfaces. Un contrat public, rien d'autre. Pensez à l’interface comme à la spécification, qui décrit comment l’application devrait être tournée vers le monde extérieur. Une spécification pour une fiche à deux broches ne précise pas (du moins je suppose que) sa structure interne. Il doit simplement être compatible avec une prise de courant .  Plug
(source: made-in-china.com )

48
Anton Gogolev

Parce que ça n'a aucun sens. Une interface est un contrat exposé publiquement. Je suis un IThing, donc je vais effectuer des méthodes IThing si demandé. Vous ne pouvez pas demander à un opérateur de vérifier qu'il utilise des méthodes dont il ne peut vous parler.

15
annakata

Les interfaces existent pour permettre aux gens d'accéder à votre classe sans savoir quelle est l'implémentation concrète. Il sépare complètement l'implémentation du contrat de transmission de données. 

Par conséquent, tout dans une interface doit être public. Les membres non publics ne sont utiles que si vous avez accès à l'implémentation et ne contribuent donc pas de manière significative à la définition d'une interface.

9
JaredPar

Les membres d'interface sont une API publique; des choses comme protected etc sont des détails d'implémentation - et les interfaces n'ont aucune implémentation. Je soupçonne que vous recherchez une implémentation d'interface explicite:

public class NavelOrange : IOrange
{
    public OrangePeel Peel { get { return new OrangePeel(); } }
    OrangePips IOrange.Seeds { get { return null; } }
}
7
Marc Gravell

Une interface est un contrat qui promet certaines fonctionnalités aux clients. En d'autres termes, le but d'une interface est de pouvoir y transtyper un type et de le transmettre comme cela au code qui a besoin des fonctionnalités garanties par cette interface. Étant donné que le code client d'un type ne peut pas accéder aux membres protégés de ce type, il est illogique de déclarer des éléments protégés dans une interface.

1
Vojislav Stojkovic

Une interface est comme la forme d'une clé.

 enter image description here

Ce n'est pas la clé.

Ce n'est pas la serrure.

C'est juste le point de contact mince.

Pour cette raison, tous les membres de l'interface (définissant la forme de la clé) doivent être publics.

Pour qu'une clé ouvre une serrure, il est important que toutes les deux partagent la même forme.

En rendant la forme (l'interface) public, vous pouvez laisser les autres créer des verrous compatibles ou des clés compatibles.

Sinon, en rendant l'interface internal, vous ne laisserez pas d'autres personnes créer des verrous compatibles ou des clés compatibles.

1
Marco Staffoli

Une interface concerne tout ce qu'un objet peut faire. Ainsi, lors de l'utilisation d'une classe implémentant cette interface, le développeur s'attend à ce que tous les membres soient implémentés. Par conséquent, le modificateur d'accès protégé ne signifie rien pour les interfaces.

0
Gerrie Schenck

Une interface ne contient que des membres publics. Protégé signifie que tout ce que vous déclarez n'est disponible que pour la classe et les instances de classe dérivées.

0
Jason Punyon

La conception actuelle des interfaces repose sur un jugement éclairé, qui offre aux développeurs une plus grande flexibilité. N'oubliez pas que très souvent, les interfaces sont écrites par des programmeurs d'infrastructure et que les implémenteurs sont des personnes différentes. Appliquer la mise en œuvre serait inutilement dur.

0
Frederick The Fool

En implémentant une interface, le type indique qu'il prend en charge un ensemble spécifique de méthodes. Si l'une de ces méthodes n'était pas publique, elle ne serait pas disponible pour les appelants et le type ne prendrait donc pas en charge l'interface indiquée. 

0
Brian Rasmussen

Toute classe qui implémente une interface .net devra inclure les implémentations de tous les membres de l'interface. De plus, toute classe peut exposer à une classe dérivée tous les membres qu’elle souhaite. Exiger qu'une implémentation d'une interface comprenne un membre qui ne sera utilisable que par des classes dérivées ne servirait à rien, sauf si (1) un tel membre pouvait être visible de l'extérieur de l'interface ou si (2) des implémentations d'interface pouvaient être utilisées membres qu’ils ne définissent pas eux-mêmes. Si les interfaces étaient autorisées à inclure des classes imbriquées (pouvant accéder aux membres protected des interfaces), les membres de l'interface protected auraient alors un sens. En effet, elles pourraient être très utiles si une classe imbriquée dans une interface pouvait définir des méthodes d'extension pour cette interface. Malheureusement, aucune installation de ce type n'existe.

BTW, même sans pouvoir imbriquer des classes dans des interfaces, il serait toujours utile d’appliquer un modificateur d’accès internal aux membres de l’interface, de sorte que seul l’Assembly dans lequel l’interface est définie puisse définir toutes les implémentations.

0
supercat