2009-08-04 4 views
5

Dans une classe de base, j'ai cette propriété:Pourquoi ne puis-je pas ajouter un accesseur défini à une propriété redéfinie?

public virtual string Text 
{ 
    get { return text; } 
} 

Je veux passer outre cela et renvoyer un texte différent, mais je voudrais aussi être en mesure de mettre le texte, donc je l'ai fait:

public override string Text 
{ 
    get { return differentText; } 
    set { differentText = value; } 
} 

Cela ne fonctionne cependant pas. Je reçois un rouge squiggly sous set en disant que je ne peux pas remplacer parce qu'il n'a pas un accesseur ensemble. Pourquoi c'est un problème? Que devrais-je faire?

+0

Je voudrais faire exactement la même chose. Devrait être possible. –

+0

C'est possible mais nécessite une "classe moyenne". En outre, ce n'est probablement pas une bonne idée dans de nombreuses situations, mais il existe quelques exceptions, par exemple lors de la substitution de propriétés abstraites. Base: 'chaîne abstraite publique Texte {get; } '. Middle (hérite de la base): 'texte de chaîne interne protégé;' public sealed override string Texte {get {return text; }} '. Child (hérite du milieu): 'public new string Texte {get {return text; } set {text = valeur; }} '. Le modificateur interne protégé et l'override scellé assurent que l'encapsulation n'est pas cassée en dehors de votre assemblée. – AnorZaken

+0

@AnorZaken: Ce n'est pas l'écrasement, c'est l'occultation. Il ne nécessite pas non plus de classe "middle". – Guffa

Répondre

3

Dans votre deuxième bloc de code que vous créez une méthode de jeu public, mais le mot « dérogation » dans la déclaration, le compilateur recherche une méthode avec la même signature dans la classe de base. Comme il ne peut pas trouver cette méthode, il ne vous permettra pas de créer votre ensemble. Comme le dit ArsenMkrt, vous pouvez modifier votre déclaration de base pour qu'elle contienne un jeu protégé. Cela vous permettra de le surcharger, mais comme vous ne pourrez toujours pas modifier la signature, vous ne pourrez pas promouvoir cette méthode en public dans votre sous-classe, donc le code que vous avez posté ne fonctionnera pas. Au lieu de cela, vous devez ajouter une méthode de jeu virtuel public à votre classe de base qui ne fait rien (ou lance même une exception si vous essayez de l'appeler) mais cela va à l'encontre de ce qu'un utilisateur de la classe attendrait le comportement de l'être si vous faites cela (et je ne le recommande) assurez-vous qu'il est si bien documenté que l'utilisateur ne peut pas manquer:

///<summary> 
///Get the Text value of the object 
///NOTE: Setting the value is not supported by this class but may be supported by child classes 
///</summary> 
public virtual string Text 
{ 
    get { return text; } 
    set { } 
} 

//using the class 

BaseClass.Text = "Wibble"; 
if (BaseClass.Text == "Wibble") 
{ 
    //Won't get here (unless the default value is "Wibble") 
} 

Sinon, le jeu déclare comme une méthode distincte votre classe enfant:

public override string Text 
{ 
    get { return differentText; } 
} 

public void SetText(string value) 
{ 
    differentText = value; 
} 
+0

Je ne l'aime pas, mais je suppose que je vais devoir faire quelque chose dans le sens d'avoir une méthode SetText séparée ou quelque chose ... merci :) – Svish

+0

Eh bien, il pourrait aussi être un problème d'architecture. Pourquoi l'utilisateur ne peut-il pas définir la valeur du texte dans la classe de base? Est-ce * vraiment * la même propriété dans les deux classes? Il semble être une exigence habituelle d'avoir besoin d'un tel motif. –

+0

Eh bien, c'est un certain nombre de classes de paramètres différentes qui contiennent différents types de valeurs. Et je voudrais qu'ils puissent tous se représenter eux-mêmes comme une valeur de texte que l'utilisateur peut lire (pour l'impression par exemple). Mais je ne veux pas que tous les paramètres soient définis par du texte (l'analyse est beaucoup plus ennuyante que l'impression). Par exemple, un paramètre de date, je veux imprimer la date, mais je n'ai pas besoin de définir la date à travers le texte, puisque le réglage sera fait avec un outil de date. – Svish

3
public virtual string Text 
{ 
    get { return text; } 
    protected set {} 
} 

changement propriété de classe de base comme celui-ci, vous essayez de remplacer la méthode ensemble qui n'existe pas

+0

Vous ne pouvez pas remplacer un setter protégé en tant que setter public dans la classe enfant. – Guffa

+0

hmm, d'accord .... :) –

2

C'est un problème car vous êtes cassé g l'encapsulation. Vous ne pouvez pas remplacer quelque chose et le rendre plus accessible, cela jetterait tout sur l'encapsulation par la fenêtre.

C'est la règle et elle s'applique aussi dans votre cas, même si vous êtes en train d'exposer quelque chose qui n'est pas la valeur d'origine.

Il n'y a aucun moyen de faire exactement ce que vous avez essayé. Vous devez soit créer un setter dans la classe de base, soit utiliser une méthode différente pour définir la nouvelle valeur.

+0

La classe enfant ne peut pas rompre l'encapsulation parce que ce qu'il fait ne peut être fait à moins que l'encapsulation était déjà cassée dans la classe de base déjà (si le l'enfant n'est pas censé pouvoir accéder au champ de sauvegarde de la propriété). De plus, la classe de base a déclaré la propriété comme virtuelle, ce qui signifie qu'elle est supposée être capable de modifier son comportement - et quand une propriété/méthode est virtuelle, tout est permis! (Tant que vous adhérez bien sûr à sa documentation.) Que ce soit _ virtuel ou non, ou si cela casse l'encapsulation de la classe de base, c'est la vraie question, et cela dépend. – AnorZaken

+0

@AnorZaken: De quoi parlez-vous? Le simple fait qu'un membre soit virtuel ne signifie pas que vous pouvez le remplacer comme bon vous semble. – Guffa

2

Vous pouvez cacher la propriété de la classe de base:

public new string Text 
{ 
    get { return differentText; } 
    set { differentText = value; } 
} 

Mais dans ce cas, cette propriété ne sera utilisée lors de la manipulation de l'objet à travers une variable de ce type, pas le type de base

2

Vous souhaitez que plus de fonctionnalités soient exposées lors de l'utilisation d'un type enfant. On dirait que vous ne voulez pas remplacer, vous voulez faire de l'ombre. Utilisez simplement le nouveau mot-clé pour masquer la propriété Text en lecture seule sous votre propriété readable/writable.

En classe de base:

protected string text; 
public string Text 
{ 
    get { return text; } 
} 

En classe dérivée:

new public string Text 
{ 
    get { return text; } 
    set { text = value; } 
} 
+0

Pouvez-vous ombrer et remplacer en même temps? – Svish

+0

Non, ils signifient des choses différentes. Que vous fassiez l'objet d'une ombre ou d'une redéfinition détermine si le comportement de Text est affecté même après la conversion au type de base. Découvrez cette question pour une meilleure explication: http://stackoverflow.com/questions/673779/what-is-shadowing –

Questions connexes