213 votes

C# - Utilisation des mots-clés virtual+override vs. new

Quelles sont les différences entre la déclaration d'une méthode dans un type de base " virtual "puis de le remplacer dans un type enfant en utilisant l'option " override "par opposition à la simple utilisation du mot clé " new "lors de la déclaration de la méthode correspondante dans le type enfant ?

3 votes

MSDN dites "Utiliser new crée un nouveau membre avec le même nom et fait en sorte que le membre original devienne caché, alors que override étend l'implémentation d'un membre hérité"

0 votes

0 votes

240voto

Orion Edwards Points 54939

Je trouve toujours ce genre de choses 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 est en fait un Bar mais nous sommes en le stockant dans une variable de type Foo (ceci est similaire à la coulée)

Ensuite, le résultat sera le suivant, selon que vous avez utilisé virtual / override o new lors de la déclaration de vos classes.

Virtual/Override explanation image

4 votes

Merci....mais pourriez-vous expliquer un peu la photo ci-dessus en ce qui concerne le casting que vous avez dit ?

0 votes

Oups Si j'ai oublié d'ajouter ces quelques lignes à mon commentaire précédent : voulez-vous dire que virtual/overriding et non-vitual/new sont utilisés uniquement pour le concept de polymorphisme et que lorsque vous déclarez simplement une variable (sans utiliser le casting) ils ne signifient rien ? Merci encore.

191voto

albertein Points 10821

Le mot clé "new" n'est pas une surcharge, 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 ());
    }
}

Cela imprime false, si vous aviez utilisé override cela aurait imprimé true.

(Code de base tiré de Joseph Daigle)

Donc, si vous faites du vrai polymorphisme, vous DOIT TOUJOURS PRÉVALOIR SUR . Le seul endroit où vous devez utiliser "new" est lorsque la méthode n'est liée en aucune façon à la version de la classe de base.

0 votes

Vous devriez revoir votre code, j'avais rendu les méthodes statiques (ce qui est valable pour l'utilisation du mot clé "new"). Mais j'ai décidé qu'il était plus clair d'utiliser des méthodes d'instance.

1 votes

Merci, j'ai manqué la partie "statique". Je devrais faire plus attention à l'avenir

1 votes

Notez que la ligne Foo test = new Bar () est cruciale ici, le mot-clé new / override pour les métodes détermine quel métode est appelé lorsque vous mettez une Bar dans une variable Foo.

45voto

Franci Penov Points 45358

Voici un peu de code pour comprendre la différence de comportement entre les 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;
    }
}

0 votes

Merci pour cela - mais pourquoi utiliser new pour "cacher" la méthode de base, alors que le simple fait de ne pas utiliser override semble faire la même chose ?

2 votes

Je ne pense pas qu'elle ait été créée pour empêcher la classe de base d'être surchargée. Je pense qu'elle a été créée pour éviter les conflits de noms, car vous ne pouvez pas surcharger une méthode qui n'est pas virtual et le compilateur se plaindra s'il voit le même nom de fonction sur une classe " bloodline " sans virtual signature

1 votes

C'est une très belle réponse. Alors new permet essentiellement à la méthode parentale de rester accessible (lorsque l'enfant est coulé/utilisé comme le type parent). Au contraire, virtual+override garantit que la méthode enfant est utilisée quelle que soit la façon dont l'enfant est coulé/utilisé (uniquement en cas de surcharge, bien sûr).

19voto

Joseph Daigle Points 16429

El new crée en fait un membre complètement 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 la réflexion et obtenez les membres du type Bar vous trouverez en fait 2 méthodes appelées DoSomething() qui sont exactement les mêmes. En utilisant new vous cachez effectivement l'implémentation dans la classe de base, de sorte que lorsque des classes dérivent de Bar (dans mon exemple) l'appel à la méthode base.DoSomething() va à Bar et non Foo .

10voto

Wedge Points 11910

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

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

Appelle la méthode VirtualFoo() de la sous-classe.

nouveau 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'elles n'ont aucune relation entre elles.

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

appellera la méthode NewBar() de la classe de base, tandis que :

(new SubClass()).NewBar()

Appelle la méthode NewBar() de la sous-classe.

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