2010-07-05 6 views
2

je code suivant. Et j'ai besoin de cacher une fonction de l'interface.Interface partiellement protégée mais sans classe abstraite

interface IOne 
{ 
    int FunctionOne(); 
} 

interface ITwo 
{ 
    double FunctionTwo(); 
} 

interface IInterfaceToImplement : IOne, ITwo 
{ 
    void AFunctionToImplement(); 
} 

public abstract MyBaseClass : TheVeryHeavyBaseClass<T, IInterfaceToImplement>, IInterfaceToImplement 
{ 
    public abstract void AFunctionToImplement(); // How to force this one to be protected? 

    public virtual int FunctionOne() { return 0; } 

    public virtual double FunctionTwo() { return 0.0; } 
} 

public MyConcreteClass : MyBaseClass 
{ 
    public override void AFunctionToImplement(); // How to force this one to be protected? 
} 

Comme vous pouvez le voir, j'ai une classe de base. Et j'ai besoin que le AFunctionToImplement() soit caché. Ai-je un mauvais design de cours? Des suggestions sur la façon de protéger la fonction d'être appelé?

EDIT. Réponse à la question Pavel Minaev dans les commentaires.

J'ai besoin chaque classe concrète de mettre en œuvre la liste des fonctions de IInterfaceToImplement. J'ai aussi besoin de chaque classe concrète pour pouvoir stocker des classes de type IInterfaceToImplement. Il s'agit d'un stockage de données arborescente. Chaque 'branche' du stockage doit effectuer les mêmes opérations que toute autre branche. Mais personne d'autre que la 'racine' et les autres 'braches' ne doivent appeler ces opérations.

EDIT2 Ma solution.

Merci Matthew Abbott et Pavel Minaev. J'ai finalement réalisé mon problème - c'est le cerveau. :)

Non, je plaisante. :) Le problème est - j'ai pensé aux classes de racine et de branche de la même branche. Maintenant, je comprends - la racine ne devrait pas implémenter IInterfaceToImplement. Voir la solution:

public class MyRootClass : IOne, ITwo 
{ 
    private IInterfaceToImplement internalData = new MyConcreteClass(); 

    public int FunctionOne() { return this.internalData.FunctionOne(); } 

    public double FunctionTwo() { return this.internalData.FunctionTwo(); } 
} 
+0

Qu'est-ce que vous essayez précisément d'atteindre? Les interfaces sont des contrats publics par définition, cela n'a tout simplement pas de sens d'avoir une définition d'interface privée. Il est parfois logique d'avoir l'implémentation particulière semi-privée, mais comme on peut toujours obtenir la référence typée par interface au même objet et appeler les méthodes d'interface, une implémentation d'interface ne peut jamais être vraiment privée non plus. Alors ... qu'est-ce que tu essayes de faire? –

Répondre

1
public class MyRootClass : IOne, ITwo 
{ 
    private IInterfaceToImplement internalData = new MyConcreteClass(); 

    public int FunctionOne() { return this.internalData.FunctionOne(); } 

    public double FunctionTwo() { return this.internalData.FunctionTwo(); } 
} 
1

Interfaces ne peuvent être définies pour les membres du public. Si vous voulez qu'une méthode soit uniquement définie comme protégée, ne créez pas d'interface et créez-la simplement en tant que membre abstrait protégé de la classe de base abstraite. Même si vous utilisiez l'interface explicite, elle serait toujours accessible au public si l'instance correspond au type d'interface associé.

public abstract MyBaseClass<T> : TheVeryHeavyBaseClass<T> 
{ 
    // remove the interface the defined this 
    protected abstract void AFunctionToImplement(); 

    // other code 
} 
+0

Je sais tout cela. Où recommanderiez-vous de déclarer le membre protégé (voir le code dans la question)? –

+0

Malheureusement, je ne peux pas changer 'TheVeryHeavyBaseClass'. Je ne suis pas sous mon contrôle. Et 'TheVeryHeavyBaseClass' ont deux paramètres génériques, le second doit être' IInterfaceToImplement' ainsi que MyBaseClass. Merci pour l'essai! –

+0

On dirait que votre propre option va implicitement implémenter l'interface. Et ensuite Création d'une seconde méthode qu'il appelle. –

2

Je suggère d'utiliser une implémentation d'interface explicite:

void IInterfaceToImplement.AFunctionToImplement(); 

... mais cela ne vous permettra pas d'exposer et de mettre en œuvre la méthode dans les sous-classes et ont encore caché. Vous voudrez peut-être repenser votre conception de classe dans ce cas.

Votre meilleur pari, il quelque chose comme ce qui suit:

public interface IMyInterface 
{ 
    void DoWork(); 
} 

public abstract class MyInterfaceBase : IMyInterface 
{ 
    /// <summary> 
    /// Forced implementation. 
    /// </summary> 
    protected abstract void DoWork(); 

    /// <summary> 
    /// Explicit implementation. 
    /// </summary> 
    void IMyInterface.DoWork() 
    { 
     // Explicit work here. 

     this.DoWork(); 
    } 
} 

Cela laisse encore les problèmes d'avoir le DoWork exposé publiquement si la méthode est appelée à partir d'une référence IMyInterface, au lieu d'une référence MyInterfaceBase. Vous ne pouvez tout simplement pas contourner cela. Si je l'ai fait ce qui suit:

MyInterface first = new MyInterface(); // Let's assume I have implemented MyInterface : MyInterfaceBase 
first.DoWork(); // Compile error, can't access method here. 

Attendu que:

IMyInterface second = new MyInterface(); 
second.DoWork(); // No problem. 

Voyez-vous la question?

+0

Je suis la bienvenue à toute conception propose! N'hésitez pas à suggérer des modifications à ma conception de classe. :) –

+1

La question est, pourquoi avez-vous besoin de cette méthode pour être caché? –

+0

Les sous-classes peuvent ré-implémenter des implémentations d'interface explicites, en fait. Ce qu'ils ne peuvent pas faire, c'est appeler l'implémentation de la classe de base via 'base' (parce que c'est effectivement privé). Mais on peut toujours aussi déclarer 'protected AFunctionToImplement' _alongside_ l'implémentation d'interface explicite, et déléguer cette dernière à la première. De cette façon, les sous-classes peuvent remplacer cette _et_ utiliser 'base'. –

1

Chaque fois que vous écrivez une interface vous déclarant implicitement une vue publique de toute classe qui implémente, donc il ne serait pas logique du tout pour essayer de cacher ses méthodes. Vous pouvez retirer AFunctionImplementation de l'interface et le laisser en direct dans la classe MyBase. Toute implémentation de la classe MyBase aurait toujours accès à celle-ci.

Dans ce cas, vous pouvez également faire en sorte que la classe MyBase implémente IOne et ITwo directement. Avoir une fonction avec le mot «Implémentation» dans son nom serait un bon indice pour éviter de le placer dans une interface, car les interfaces sont souvent utilisées comme un moyen d'isoler l'utilisation des détails d'implémentation.

+0

Je pensais que votre suggestion.Le problème est le deuxième paramètre générique de 'TheVeryHeavyBaseClass' et le MyBaseClass doit implémenter la même interface unique (mais pas deux) –

1

Peut-être que vous pouvez faire la méthode virtuelle dans la classe abstraite, puis lancer une exception

/// <summary> 
    /// Available only in derived classes 
    /// </summary> 
    public virtual void AFunctionToImplement2() 
    { 
     throw new ProtectedMethodException("Please do not call this method in the base class:) "); 
    } 

Je ne sais pas si cela est une solution stupide, mais au moins vous ne permettent pas aux utilisateurs de utilisez la méthode même si elle est publique.

+0

C'est la façon dont les classes sont mises en œuvre pour le moment. :) Et je suis essayant d'éviter cela. –

Questions connexes