11
votes

Pourquoi ne puis-je pas ajouter un accesseur de set à une propriété de remplacement?

dans une classe de base, j'ai cette propriété: xxx

Je veux remplacer cela et renvoyer un texte différent, mais je voudrais aussi pouvoir définir le texte, alors je l'ai fait Ceci: xxx

Cela ne fonctionne pas. Je reçois un rouge squigly sous définir disant que je ne peux pas remplacer, car il n'a pas d'accesseur défini. Pourquoi c'est un problème? Que dois-je faire?


8 commentaires

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


Il 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 y a des exceptions, par exemple lorsqu'il remplace les propriétés abstraites. Base: texte abstrait public {obtenir; } . Milieu (Hérités Base): Texte de chaîne interne protégé; Scellé du public Texte de chaîne Scellé {Obtenir {Texte de retour; }} . Enfant (hériter au milieu): Nouvelle chaîne de chaîne publique {Obtenir {Texte de retour; } SET {texte = valeur; }} . Le modificateur interne protégé et le remplacement scellé assure l'encapsulation ne sont pas cassés à l'extérieur de votre assemblage.


@Anorzaken: Cela ne remplace pas, c'est ombrage. Cela ne nécessite pas non plus une classe "moyenne".


@Guffa Il est à la fois de remplacer et de nuire, et puisque c # ne permet pas à la fois dans la même classe, la classe moyenne est nécessaire.


@Anorzaken: Cela ne peut pas être les deux, ombragers ne remplace pas. Le remplacer dans une classe moyenne ne le rend pas remplacé dans la classe enfant, il est toujours ombré.


@Guffa bien sûr. Je n'ai jamais dit qu'il faisait la fois dans la même classe ... J'ai dit que vous ne pouvez pas faire à la fois dans la même classe et que vous avez répondu avec "Vous ne pouvez pas faire les deux dans la même classe" ...? C'est très probablement ce que l'OP voulait faire, et c'est simule à la fois primordial et ombrageuse grâce au champ interne protégé. Et non, cela ne fonctionnerait pas dans les assemblées, et non, il ne fait pas techniquement les deux, mais ce n'était rien l'OP qui ne lui demandait pas.


@Anorzaken: Non, cela ne simule pas le dépassement. L'observation est juste ombragée, avoir une classe moyenne ne change pas cela, et ce n'est pas nécessaire pour l'ombre de la propriété.


@Guffa cherche plus près le code. L'ombrage étant fait se comporter de manière indistinctement de remplacer (qui convient à la définition de simule Spot sur) et ce comportement ne peut pas être apporté à compiler sans la classe moyenne, période. Je vous défie d'écrire du code que se comporte exactement comme si c'était remplacé mais ajoute un accesseur de jeu qui ne nécessite pas une classe moyenne. Si vous essayez réellement, vous trouverez que c'est impossible. Si vous pensez que mon code est incorrect, je vous défie d'écrire un test qui montre que mes revendications sont fausses. Sauf si vous utilisez la réflexion, vous trouverez que cela est impossible aussi.


5 Réponses :


5
votes
public virtual string Text 
{
    get { return text; }
    protected set {}
}
change base class property like this, you are trying to override set method that doesn't exist

1 commentaires

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



5
votes

Dans votre deuxième bloc de code, vous créez une méthode de jeu public, mais le mot "remplacement" dans la déclaration permet au compilateur de rechercher 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 Arsenmkrt dit que vous pouvez modifier votre déclaration de base pour contenir un ensemble protégé. Cela vous permettra de le remplacer, mais puisque vous ne pourrez toujours pas modifier la signature, vous ne pouvez pas promouvoir cette méthode au public dans votre sous-classe, le code que vous avez affiché ne fonctionnera toujours pas. < p> Au lieu de cela, vous devez ajouter une méthode de jeu virtuel public à votre classe de base qui ne fait rien (ou même une exception si vous essayez de l'appeler) mais cela va à l'encontre de ce que l'utilisateur de la classe attendrait le comportement Pour être si si vous faites cela (et je ne le recommanderai pas) Assurez-vous qu'il est si bien documenté que l'utilisateur ne peut pas le manquer: xxx

sinon déclarer le Définissez comme une méthode distincte dans votre classe enfant: xxx


3 commentaires

Je n'aime pas ça, mais je suppose que je devrais faire quelque chose dans le sens d'avoir une méthode Settext Secretext ou quelque chose ... merci :)


Eh bien, cela pourrait aussi être une question architecturale. Pourquoi l'utilisateur ne peut-il pas définir la valeur de texte dans la classe de base? Est-ce vraiment la même propriété dans les deux classes? Il semble être une condition habituelle d'avoir besoin d'un motif comme celui-ci.


Eh bien, il s'agit d'un certain nombre de classes de paramètres différents qui contiennent différents types de valeurs. Et j'aimerais que tous puissent se représenter 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 le texte (l'analyse est beaucoup plus gênante que l'impression). Par exemple, un paramètre de date, je souhaite imprimer la date, mais je n'ai pas besoin de définir la date via le texte, car le réglage sera effectué avec un datationPicker.



2
votes

C'est un problème parce que vous enfreignez l'encapsulation. Vous ne pouvez pas remplacer quelque chose et le rendre plus accessible, cela jetterait tout sur l'encapsualtion de la fenêtre.

C'est la règle et il s'applique également dans votre cas, car vous exposez effectivement quelque chose qui n'est pas la valeur initiale.

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


2 commentaires

La classe enfant ne peut pas casser l'encapsulation car ce qu'il fait ne peut pas être fait à moins que l'encapsulation était déjà brisée dans la classe de base déjà (si l'enfant n'est pas censé pouvoir accéder au champ de support de la propriété). De plus, la classe de base a déclaré que la propriété est virtuelle, ce qui signifie qu'il est supposé être possible de modifier son comportement - et lorsqu'une propriété / méthode est virtuelle quelque chose va! (Tant que vous adhérez à sa documentation bien sûr.) Que ce soit devrait être virtuel, ou si cela enfreint l'encapsulation de la classe de base, est la vraie question, et cela dépend.


@Anorzaken: De quoi parlez-vous? Juste parce qu'un membre est virtuel ne signifie pas que vous pouvez le remplacer comme vous le souhaitez.



2
votes

Vous pouvez masquer la propriété à partir de la classe de base: xxx

mais dans ce cas, la propriété ne sera utilisée que lorsque la manipulation de l'objet à travers une variable de ce type, et non le type de base < / p>


0 commentaires

3
votes

Vous voulez que plus de capacités soient exposées lors de l'utilisation d'un type d'enfant. On dirait que vous ne voulez pas remplacer, vous voulez ombre. Il suffit d'utiliser le nouveau mot-clé pour masquer la propriété de texte réadonnée sous votre propriété lisible / écritable.

dans la classe de base: p> xxx pré>

en classe dérivée: p>

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


2 commentaires

Pouvez-vous ombre et remplacer en même temps?


Non, ils signifient différentes choses. Que vous ombragez ou moins vous détermine si le comportement du texte est affecté même après la mise au point sur le type de base. Consultez cette question pour une meilleure explication: Stackoverflow.com/questions/673779/What-is-shading