Pourquoi est-ce que je ne peux pas utiliser virtual / override sur des variables de classe comme je peux sur des méthodes?
Dans l'exemple suivant, je suis en mesure de créer un virtuel méthode Show()
dans le hérité classe et puis remplacer dans le hériter classe.
Je veux faire de la même chose avec le protégé variable de classe prefix
mais j'obtiens l'erreur:
Le modificateur "virtuel" n'est pas valide
pour cet article
Mais puisque je ne peux pas définir cette variable comme virtuel/remplacer dans mes classes, j'ai le compilateur avertissement:
TestOverride234355.SecondaryTransaction.préfixe'
masque membre hérité
'TestOverride234355.Des transactions.préfixe'.
Utiliser le mot clé new si cachette était
prévu.
Heureusement, lorsque j'ajoute le new
mot-clé tout fonctionne très bience qui est normal puisque je obtenir la même fonctionnalité, mais cela soulève deux questions:
- Pourquoi je peux utiliser virtual/remplacer des méthodes, mais pas pour les protégés de variables de classe?
- Quelle est la différence entre le virtuel/remplacement d'approche et de la peau-il-avec-la nouvelle approche depuis au moins dans cet exemple, ils offrent la même fonctionnalité?
Code:
using System;
namespace TestOverride234355
{
public class Program
{
static void Main(string[] args)
{
Transaction st1 = new Transaction { Name = "name1", State = "state1" };
SecondaryTransaction st2 =
new SecondaryTransaction { Name = "name1", State = "state1" };
Console.WriteLine(st1.Show());
Console.WriteLine(st2.Show());
Console.ReadLine();
}
}
public class Transaction
{
public string Name { get; set; }
public string State { get; set; }
protected string prefix = "Primary";
public virtual string Show()
{
return String.Format("{0}: {1}, {2}", prefix, Name, State);
}
}
public class SecondaryTransaction : Transaction
{
protected new string prefix = "Secondary";
public override string Show()
{
return String.Format("{0}: {1}, {2}", prefix, Name, State);
}
}
}
source d'informationauteur Edward Tanguay
Vous devez vous connecter pour publier un commentaire.
Substitution d'un champ n'a pas vraiment de sens. Il fait partie de l'état de la classe de base, et si une classe qui hérite veut le changer, il devrait être changable dans la classe qui hérite en lui donnant une bonne visibilité.
Une chose que vous pourriez faire dans votre cas est de
prefix
dans le constructeur de la classe qui hérite:Vous pouvez également faire une propriété au lieu d'un champ, et de rendre la propriété virtuelle. Cela vous permettra de modifier le comportement de la lecture et de définition de la propriété dans la classe qui hérite:
EDIT: Comme pour votre question d'utiliser une variable dans un constructeur de base avant d'hériter de la classe a mis en elle, une façon de résoudre ce problème est de définir une méthode d'initialisation de la classe de base, de la remplacer dans la classe qui hérite, et l'appeler à partir du constructeur de base avant d'accéder à tous les champs:
EDIT 2: - Vous également demandé à ce que la différence entre le virtuel/remplacer et le nom se cacher (le nouveau mot-clé sur les méthodes) est, si il devrait être évité, et si elle peut être utile.
Nom de masquage est une fonctionnalité qui rompt l'héritage dans le cas de masquage des méthodes virtuelles. I. e., si vous masquez le
Initialize()
méthode dans la classe enfant, la classe de base ne vont pas le voir, et de ne pas appeler. Aussi, si leInitialize()
méthode a été publique, le code externe qui appelaitInitialize()
sur une référence de type de base serait d'appelerInitialize()
sur le type de base.Nom de masquage est utile lorsqu'une méthode est non-virtuelle dans une classe de base, et un enfant veut donner une différents mise en œuvre de son propre. Notez, cependant, que c'est PAS le même que virtuel/remplacer. Les références de la base type d'appeler le type de base de la mise en œuvre, et les références de l'enfant type d'appeler l'enfant type de mise en œuvre.
Plutôt créer une propriété pour le préfixe membre - de cette façon, vous pouvez définir la propriété virtuelle/abstract
Champs sont utilisés pour stocker l'état d'un objet, ils contribuent à l'objet encapsuler les données et masquer la mise en œuvre des préoccupations des autres. En étant en mesure de remplacer un domaine qui nous fuit la mise en œuvre des préoccupations de la classe de code du client (y compris les sous-types). Pour cette raison, la plupart des langues ont pris la décision qu'on ne peut pas définir les variables d'instance qui peut être remplacée (bien qu'ils puissent être public/protected... donc vous pouvez y accéder).
Vous aussi ne peut pas mettre les variables d'instance dans une interface
Statique ou non virtuelle méthode ou une propriété est une adresse de mémoire (pour simplifier les choses). Une méthode virtuelle ou bien est identifié par une entrée dans une table. Ce tableau dépend de la classe définissant la méthode ou la propriété.
Lorsque vous remplacez un membre virtuel dans une classe dérivée, vous modifiez en fait l'entrée dans le tableau de la classe dérivée au point de la méthode de remplacement.
Au moment de l'exécution, l'accès à un tel membre va bien la table, toujours. Donc, l'entrée peut être remplacée par n'importe quelle classe dérivée.
Il n'y a pas de tel mécanisme pour les champs, comme ils sont destinés à être accessibles rapidement.
À l'aide de "nouveau" sur un membre signifie que vous ne souhaitez pas remplacer l'entrée dans la table, mais que vous voulez un nouveau membre (avec le même nom qu'un virtuel existant, une mauvaise pratique si vous me demandez).
Si vous accédez à un membre virtuel par l'intermédiaire d'un pointeur vers la classe de base, vous n'aurez jamais accès défini comme "nouveau" dans la classe dérivée, qui est la différence mentionné dans la deuxième partie de votre question.
Dans votre exemple, si vous n'avez pas de remplacer "Show" dans le SecondaryTransaction classe, puis l'appel de Montrer sur un exemple de SecondaryTransaction serait en réalité l'appel de la méthode dans la classe de base (Transaction), qui serait donc utiliser "Afficher" dans la classe de base, résultant en sortie de:
L'affirmative, selon quelle méthode appeler (c'est à dire l'un sur la base de la classe ou de l'enfant de la classe), le code aurait une valeur différente de "préfixe", ce qui serait une maintenabilité cauchemar. Je soupçonne ce que vous voulez probablement pour/doit faire, c'est exposer une propriété de la Transaction qui s'enroule "préfixe".
Vous ne pouvez pas remplacer un champ parce que c'est un détail de l'implémentation de la classe de base. Vous pouvez modifier la valeur d'un champ protégé, mais en la remplaçant vous pensez peut-être en disant: je veux remplacer la champpas la valeur.
Ce que je ferais (si je absolument ne voulais pas/ne pouvait pas utiliser les propriétés) :
Edit: (Comme pour mon commentaire sur une autre réponse)
Si vous appelez dans votre classe de base ctor et ont besoin de la valeur définie, alors vous devrez probablement modifier Transaction, éventuellement comme ceci:
Pourquoi voulez-vous remplacer protégé variable, sûrement tout ce que vous voulez faire est de mettre autre chose dans la classe prioritaire (éventuellement dans le constructeur)?
Vous ne pouvez pas car il n'est pas utiliser. Que voulez-vous accomplir en substituant un champ?
Substitution d'un champ est un non-sens. Le champ marquage comme vous protège automatiquement puisse y avoir accès dans les classes dérivées. Vous pouvez remplacer les fonctions, propriétés, car il utilise des fonctions à l'interne.