web-dev-qa-db-fra.com

Qu'est-ce que Shadowing?

En C #, que signifie le terme shadowing? J'ai lu ce lien mais je ne l'ai pas bien compris.

34
james

Shadowing cache une méthode dans une classe de base. En utilisant l'exemple de la question que vous avez liée:

class A 
{
   public int Foo(){ return 5;}
   public virtual int Bar(){return 5;}
}
class B : A
{
   public new int Foo() { return 1;}
   public override int Bar() {return 1;}
}

La classe Bremplace la méthode virtuelle Bar. Il cache (ombres) la méthode non virtuelle Foo. La substitution utilise le mot-clé override . L'observation est effectuée avec le mot-clé new .

Dans le code ci-dessus, si vous n'avez pas utilisé le mot clé new lors de la définition de la méthode Foo dans la classe B, vous obtiendrez cet avertissement du compilateur:

'test.B.Foo()' hides inherited member 'test.A.Foo()'. Use the new keyword if hiding was intended.
45
Jim Mischel
  • Remplacement: redéfinition d'une méthode existante sur une classe de base
  • Shadowing: création d'une méthode entièrement nouvelle avec la même signature que celle d'une classe de base
32
Kent Boogaart

Supposons que j'ai une classe de base qui implémente une méthode virtuelle:

public class A
{
    public virtual void M() { Console.WriteLine("In A.M()."); }
}

J'ai aussi une classe dérivée qui définit également une méthode M:

public class B : A
{
    // could be either "new" or "override", "new" is default
    public void M() { Console.WriteLine("In B.M()."); }
}

Supposons maintenant que j'écris un programme comme celui-ci:

A alpha = new B(); // it's really a B but I cast it to an A
alpha.M();

J'ai deux choix différents quant à la manière dont je souhaite que cela soit mis en œuvre. Le comportement par défaut consiste à appeler la version de M. de A (ce comportement est identique si vous avez appliqué le mot clé "new" à B.M().)

Cela s'appelle "shadowing" quand nous avons une méthode avec le même nom mais un comportement différent quand elle est appelée depuis la classe de base.

Alternativement, nous aurions pu spécifier "override" sur B.M(). Dans ce cas, alpha.M() aurait appelé la version de M. de B.

20
mquander

L’observation consiste à masquer une méthode de classe de base avec une nouvelle définition dans une classe enfant.

La différence entre masquer et annuler dépend de la façon dont les méthodes sont appelées. 

Ainsi, lorsqu'une méthode virtuelle est remplacée, l'adresse d'appel de la table d'appel de méthode de la classe de base est remplacée par l'adresse de la routine enfant.

En revanche, lorsqu'une méthode est masquée, une nouvelle adresse est ajoutée à la table d'appels à la méthode de la classe enfant.

Lorsqu'un appel est fait à la méthode en question:

  1. Le type de classe de table d'appel de méthode est obtenu; si nous appelons avec une référence à la classe de base, la table de méthode de classe de base est obtenue, si nous avons une référence à la classe enfant, la table de méthode de classe enfant est obtenue.
  2. La méthode est recherchée dans la table. Si elle est trouvée, l'invocation a lieu. Sinon, la table de la méthode de la classe de base est recherchée.

Si nous appelons la méthode avec une référence à la classe enfant alors le comportement est le même, si la méthode a été remplacée, l'adresse de la méthode sera trouvée dans la classe de base, si la méthode est masquée, l'adresse de la méthode sera trouvée sur le classe enfant, et comme elle a déjà été trouvée, la table de classe de base ne fera pas l'objet d'une recherche.

Si nous appelons la méthode avec une référence à la classe de base, le comportement change. Lors de la substitution, l'adresse de la méthode écrasant l'entrée de la classe de base, nous appellerons la méthode enfant, même si vous tenez une référence à la classe de base. Avec shadowing, la table de méthode de la classe de base (qui est la seule visible car nous tenons une référence à la classe de base) contient l'adresse de la méthode virtuelle et, par conséquent, la méthode de la classe de base sera appelée.

En général, l'observation est une mauvaise idée, car elle introduit une différence dans le comportement d'une instance en fonction de la référence que nous avons à celle-ci.

10
Jorge Córdoba

Développer la bonne réponse de Kent 

Quand je ne sais pas quand la méthode sera appelée, j’aime penser à l’observation par rapport à l’annulation suivante

  • Shadowing: la méthode appelée dépend du type de référence au point où l'appel est effectué
  • Remplacement: la méthode appelée dépend du type de l'objet au moment où l'appel est effectué. 
8
JaredPar

Voici un article MSDN sur Shadowing. Les exemples de langage sont en Visual Basic (malheureusement, il n’ya pas de page C # équivalente sur MSDN), mais elle traite généralement des concepts et devrait vous aider à comprendre quand même.

Edit: On dirait qu'il y a est un article C # sur l'observation, à l'exception du fait qu'il s'appelle masquage en C #. En outre, cette page offre un bon aperçu.

3
Noldorin

Si vous souhaitez masquer la méthode de la classe de base, utilisez override in base [méthode virtuelle dans base]

si vous souhaitez masquer la méthode de classe enfant, utilisez new in base [méthode non virtuelle à base] -> shadow

Base B=new Child()

B.VirtualMethod() -> Appelle la méthode de classe enfant

B.NonVirtualMethod() -> Appelle la méthode de la classe de base

2
Mathew M

Remplacement : même nom et exactement les mêmes paramètres, implémentés différemment dans les sous-classes.

  • Si elle est traitée comme DerivedClass ou BaseClass, elle utilise une méthode dérivée.

Shadowing : même nom et exactement les mêmes paramètres, implémentés différemment dans les sous-classes.

  • Si elle est traitée comme DerivedClass, elle utilise une méthode dérivée.
  • s'il est traité comme BaseClass, il utilise la méthode de base.
0
Kamran Bigdely

J'espère que cette brève explication aide.

Shadowing- Remplace l'élément complet de la classe parente 

class InventoryAndSales
{
    public int InvoiceNumber { get; set; }
}

//if someone calls for this class then the InvoiceNumber type is now object 
class NewInventoryAndSales : InventoryAndSales
{
    public new object InvoiceNumber { get; set; }
}



Overriding- Ne remplace que l'implémentation. Il ne remplace pas le type de données qu'il ne remplace pas, comme par exemple si vous avez une variable, il ne la convertit pas en méthode. Ainsi, s'il existe une méthode, elle utilisera cette méthode et ne modifiera que l'implémentation.

 class InventoryAndSales
    {
        public virtual int GetTotalSales(int a, int b)
        {
            return a + b;
        }
    }


    class NewInventoryAndSales : InventoryAndSales
    {
        //it replaces the implementation in parent class
        public override int GetTotalSales(int a, int b)
        {
            return a * b;
        }
    }
0
davinceleecode