54 votes

Utiliser un nouveau mot-clé si la dissimulation était prévue

J'ai le bout de code suivant qui génère l'avertissement "Use new keyword if hiding was intended" dans VS2008 :

public double Foo(double param)
{
   return base.Foo(param);
}

Le site Foo() dans la classe de base est protégée et je veux l'exposer à un test unitaire en la plaçant dans une classe wrapper uniquement dans le but de faire des tests unitaires. C'est-à-dire que la classe wrapper ne sera pas utilisée pour autre chose. J'ai donc une question à poser : Est-ce une pratique acceptée ?

Retour à la new avertissement. Pourquoi devrais-je remplacer la fonction de remplacement dans ce scénario ?

69voto

Marc Gravell Points 482669

Le site new permet d'indiquer clairement que l'on sait que l'on écrase une méthode existante. Puisque le code existant était protected il n'y a pas de problème - vous pouvez ajouter sans risque l'option new pour l'empêcher de gémir.

La différence survient lorsque votre méthode fait quelque chose de différent ; toute variable qui fait référence à la méthode dérivé de et appelle Foo() fera quelque chose de différent (même avec le même objet) de celui qui fait référence à l'objet base et appelle Foo() :

SomeDerived obj = new SomeDerived();
obj.Foo(); // runs the new code
SomeBase objBase = obj; // still the same object
objBase.Foo(); // runs the old code

Cela pourrait évidemment avoir un impact sur tout code existant qui connaît les SomeDerived et appelle Foo() - c'est-à-dire qu'il exécute maintenant une méthode complètement différente.

Notez également que vous pourriez le marquer protected internal et utiliser [InternalsVisibleTo] pour donner accès à votre test unitaire (il s'agit de l'utilisation la plus courante de l'option [InternalsVisibleTo] ; vos tests unitaires peuvent alors y accéder directement sans la classe dérivée.

38voto

Jon Skeet Points 692016

La clé est que vous pas en surchargeant la méthode. Vous la cachez. Si tu la remplaçais, tu aurais besoin de la méthode override (à ce moment-là, à moins qu'il ne soit virtuel, le compilateur se plaindrait parce que vous avez utilisé le mot-clé ne peut pas remplacer une méthode non virtuelle).

Vous utilisez le new mot-clé pour dire à la fois au compilateur et à toute personne lisant le code, "C'est bon, je sais que cela ne fait que cacher la méthode de base et ne la surcharge pas - c'est ce que je voulais faire".

Franchement, je pense que c'est rarement une bonne idée de cacher des méthodes - j'utiliserais un nom de méthode différent, comme Craig l'a suggéré - mais c'est une autre discussion.

8voto

Craig Stuntz Points 95965

Vous changez la visibilité sans le nom. Appelez votre fonction TestFoo et cela fonctionnera. Oui, IMHO, il est acceptable de sous-classer pour cette raison.

1voto

Perret Points 43

Vous trouverez toujours des situations délicates dans lesquelles le new Le mot-clé peut être utilisé pour se cacher alors qu'il peut être évité la plupart du temps.

Cependant, récemment, j'ai vraiment eu besoin de ce mot-clé, principalement parce que le langage ne dispose pas d'autres fonctionnalités synthétiques appropriées pour compléter un accesseur existant, par exemple :

Si vous considérez un cours à l'ancienne comme :

KeyedCollection<TKey, TItem>

Vous remarquerez que l'accesoire pour accéder aux éléments par l'index est :

TItem this[Int32 index] { get; set; }

A la fois { get; set; } et ils sont bien sûr obligatoires en raison de l'héritage relatif aux ICollection<T> y Collection<T> mais il n'y a qu'un seul { get; } pour accéder aux objets par l'intermédiaire de leurs clés (j'ai quelques suppositions sur cette conception et il y a beaucoup de raisons pour cela, donc notez que j'ai pris le KeyedCollection<TKey, TItem>) à titre d'illustration).

De toute façon, il n'y a qu'un seul getter pour l'accès aux clés :

TItem this[TKey key] { get; }

Mais qu'en est-il si je veux ajouter le { set; } support, techniquement parlant ce n'est pas si stupide surtout si vous continuez à raisonner à partir de l'ancienne définition de la propriété, c'est juste une méthode... la seule façon est d'implémenter explicitement une autre interface factice mais quand vous voulez faire de l'implicite vous devez venir avec l'interface new mot-clé, je cache la définition de l'accesseur, je garde la définition de la base get ; et j'ajoute juste un ensemble rempli de quelques choses personnelles pour que ça fonctionne.

Je pense que pour ce scénario très spécifique, ce mot-clé est parfaitement applicable, en particulier dans un contexte où il n'y a pas d'apport à l'activité de l'entreprise. { get; } partie.

  public new TItem this[TKey key]
  { 
      get { return base... }
      set { ... }
  }

C'est à peu près la seule astuce pour éviter ce genre d'avertissement car le compilateur vous suggère que vous cachez peut-être sans vous en rendre compte ce que vous faites.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X