web-dev-qa-db-fra.com

C # - utilisation des mots clés virtuelle + substitution par rapport à nouveau

Quelles sont les différences entre la déclaration d'une méthode dans un type de base "virtual" et son remplacement dans un type enfant à l'aide du mot clé "override" par opposition à l'utilisation simple du mot clé "new" pour déclarer la méthode correspondante dans le type enfant? 

193
i3ensays

Le mot-clé "nouveau" ne remplace pas, il signifie une nouvelle méthode qui n'a rien à voir avec la méthode de la classe de base. 

public class Foo
{
     public bool DoSomething() { return false; }
}

public class Bar : Foo
{
     public new bool DoSomething() { return true; }
}

public class Test
{
    public static void Main ()
    {
        Foo test = new Bar ();
        Console.WriteLine (test.DoSomething ());
    }
}

Ceci imprime faux, si vous utilisiez le remplacement, il aurait été imprimé vrai.

(Code de base tiré de Joseph Daigle)

Donc, si vous faites un vrai polymorphisme vous DEVRAIENT TOUJOURS SUPPRIMER . Le seul endroit où vous devez utiliser "nouveau" est lorsque la méthode n'est en aucun cas liée à la version de la classe de base.

174
albertein

Je trouve toujours des choses comme celle-ci plus faciles à comprendre avec des images:

Encore une fois, en prenant le code de Joseph Daigle,

public class Foo
{
     public /*virtual*/ bool DoSomething() { return false; }
}

public class Bar : Foo
{
     public /*override or new*/ bool DoSomething() { return true; }
}

Si vous appelez ensuite le code comme ceci:

Foo a = new Bar();
a.DoSomething();

NOTE: L'important est que notre objet soit en fait une Bar, mais nous sommes en le stockant dans une variable de type Foo (cela revient à le lancer}

Le résultat sera alors le suivant, selon que vous ayez utilisé virtual/override ou new lors de la déclaration de vos classes.

 Virtual/Override explanation image

218
Orion Edwards

Voici un code pour comprendre la différence de comportement des méthodes virtuelles et non virtuelles:

class A
{
    public void foo()
    {
        Console.WriteLine("A::foo()");
    }
    public virtual void bar()
    {
        Console.WriteLine("A::bar()");
    }
}

class B : A
{
    public new void foo()
    {
        Console.WriteLine("B::foo()");
    }
    public override void bar()
    {
        Console.WriteLine("B::bar()");
    }
}

class Program
{
    static int Main(string[] args)
    {
        B b = new B();
        A a = b;
        a.foo(); // Prints A::foo
        b.foo(); // Prints B::foo
        a.bar(); // Prints B::bar
        b.bar(); // Prints B::bar
        return 0;
    }
}
41
Franci Penov

Le mot clé new crée en fait un membre entièrement nouveau qui n'existe que sur ce type spécifique.

Par exemple

public class Foo
{
     public bool DoSomething() { return false; }
}

public class Bar : Foo
{
     public new bool DoSomething() { return true; }
}

La méthode existe sur les deux types. Lorsque vous utilisez réflexion et récupérez les membres de type Bar, vous trouverez 2 méthodes appelées DoSomething() qui ont exactement la même apparence. En utilisant new, vous masquez efficacement l'implémentation dans la classe de base. Ainsi, lorsque les classes dérivent de Bar (dans mon exemple), l'appel de méthode à base.DoSomething() passe à Bar et non à Foo.

19
Joseph Daigle

virtual/override indique au compilateur que les deux méthodes sont liées et que, dans certaines circonstances, lorsque vous penseriez appeler la première méthode (virtuelle), il est en fait correct d'appeler la deuxième méthode (surchargée). C'est le fondement du polymorphisme.

(new SubClass() as BaseClass).VirtualFoo()

Appellera la méthode VirtualFoo () remplacée par la SubClass.

new indique au compilateur que vous ajoutez une méthode à une classe dérivée portant le même nom qu'une méthode de la classe de base, mais qu'ils n'ont pas de relation les uns avec les autres.

(new SubClass() as BaseClass).NewBar()

Appellera la méthode NewBar () de BaseClass, alors que:

(new SubClass()).NewBar()

Appellera la méthode NewBar () du SubClass.

9
Wedge

Au-delà des détails techniques, je pense que l’utilisation de virtual/override communique beaucoup d’informations sémantiques sur la conception. Lorsque vous déclarez une méthode virtuelle, vous indiquez que vous vous attendez à ce que les classes d'implémentation veuillent fournir leurs propres implémentations, autres que celles par défaut. De même, omettre cela dans une classe de base déclare également que la méthode par défaut devrait suffire pour toutes les classes implémentées. De même, on peut utiliser des déclarations abstraites pour forcer les classes d'implémentation à fournir leur propre implémentation. Encore une fois, je pense que cela communique beaucoup sur la manière dont le programmeur s'attend à ce que le code soit utilisé. Si j'écrivais à la fois les classes de base et d'implémentation et que je me retrouvais avec de nouvelles méthodes, je repenserais sérieusement la décision de ne pas rendre la méthode virtuelle dans le parent et de déclarer mon intention de manière spécifique.

8
tvanfosson

La différence entre le mot clé override et le nouveau mot clé réside dans le fait que la première méthode remplace la méthode et la dernière la masque.

Consultez les liens suivants pour plus d'informations ...

MSDN et Autres

4
Nescio
  • new mot-clé est pour Cacher. - signifie que vous cachez votre méthode au moment de l'exécution. La sortie sera basée sur la méthode de la classe de base.
  • override pour passer outre. - signifie que vous appelez votre méthode de classe dérivée avec la référence de classe de base. La sortie sera basée sur la méthode de la classe dérivée.
3
Chetan

Ma version de l'explication provient de l'utilisation de properties pour aider à comprendre les différences.

override est assez simple, non? Le type sous-jacent annule celui du parent.

new est peut-être trompeur (pour moi c'était). Avec les propriétés, il est plus facile de comprendre:

public class Foo
{
    public bool GetSomething => false;
}

public class Bar : Foo
{
    public new bool GetSomething => true;
}

public static void Main(string[] args)
{
    Foo foo = new Bar();
    Console.WriteLine(foo.GetSomething);

    Bar bar = new Bar();
    Console.WriteLine(bar.GetSomething);
}

En utilisant un débogueur, vous remarquerez que Foo foo a les propriétés 2 GetSomething, car il possède deux versions de la propriété, Foo 's et Bar' s, et savoir laquelle utiliser, c # "sélectionne" la propriété pour le type actuel. 

Si vous vouliez utiliser la version de la barre, vous auriez utilisé le remplacement ou utiliser Foo foo à la place.

Bar bar a seulement 1 , car il veut complètement nouveau comportement pour GetSomething.

1
Dror Weiss

Ne pas marquer une méthode avec quoi que ce soit signifie: Lier cette méthode en utilisant le type de compilation de l'objet, pas le type à l'exécution (liaison statique). 

Marquer une méthode avec virtual signifie: Lier cette méthode en utilisant le type d'exécution de l'objet, pas le type à la compilation (liaison dynamique). 

Marquer une méthode de classe de base virtual avec override dans une classe dérivée signifie: Il s'agit de la méthode à lier à l'aide du type d'exécution de l'objet (liaison dynamique). 

Marquer une méthode virtual de classe de base avec new dans une classe dérivée signifie: Il s’agit d’une nouvelle méthode qui n’a aucune relation avec celle qui porte le même nom dans la classe de base et doit être liée à l’aide du type de compilation de l’objet (liaison statique). 

Ne pas marquer une méthode de classe de base virtual dans la classe dérivée signifie: Cette méthode est marquée comme new (liaison statique). 

Marquer une méthode abstract signifie: Cette méthode est virtuelle, mais je ne déclarerai pas de corps pour elle et sa classe est également abstraite (liaison dynamique). 

0
Emre Tapcı