Question

Quelles sont les différences entre la déclaration d'une méthode dans un type de base " virtual " puis le remplacer dans un type enfant à l'aide de l'option " override ". mot-clé au lieu d'utiliser simplement le " nouveau " mot-clé lors de la déclaration de la méthode correspondante dans le type enfant?

Était-ce utile?

La solution

Le " nouveau " mot-clé ne remplace pas, cela signifie une nouvelle méthode qui n'a rien à voir avec la méthode de 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 affiche false, si vous utilisiez le remplacement, le résultat serait true.

(code de base tiré de Joseph Daigle)

Ainsi, si vous effectuez un véritable polymorphisme, vous devez toujours annuler . Le seul endroit où vous devez utiliser " new " est le moment où la méthode n’a aucun lien avec la version de la classe de base.

Autres conseils

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 suit:

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

REMARQUE: l'important est que notre objet soit en réalité une Bar , mais nous le stockons dans une variable de type Foo (cela ressemble à le lancer)

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

 image d'explication virtuelle / substitution

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;
    }
}

Le mot clé new crée en réalité 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 la réflexion et obtenez les membres de type Bar , vous trouverez en fait deux méthodes appelées DoSomething () qui ont exactement la même apparence. En utilisant new , vous cachez effectivement 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 ( ) va dans Bar et non pas Foo .

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

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

Appellera la méthode VirtualFoo () annulée de la sous-classe.

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 aucun lien entre eux.

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

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

(new SubClass()).NewBar()

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

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 façon dont le programmeur s'attend à ce que le code soit utilisé. Si j’écrivais les classes de base et d’implémentation et que j’utilisais new, 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.

La différence entre le mot-clé override et le nouveau mot-clé réside dans le fait que la première méthode est surchargée et que la dernière méthode le cache.

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

MSDN et Autres

    Le mot clé
  • new est destiné à Masquer. - 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.
  • écraser pour écraser. - 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.

Ma version de l'explication provient de l'utilisation de propriétés pour mieux comprendre les différences.

remplacer est assez simple, non? Le type sous-jacent remplace le 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);
}

À l'aide d'un débogueur, vous pouvez constater que Foo foo a des propriétés 2 GetSomething , car il en existe deux versions, Foo et Barres et savoir lequel utiliser, c # "picks "" la propriété pour le type actuel.

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

La barre n'a que 1 , car elle souhaite un nouveau comportement pour GetSomething .

Ne marquer aucune méthode avec une méthode signifie: Liez 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: liez cette méthode en utilisant le type d'exécution de l'objet, pas le type de compilation (liaison dynamique).

Marquer une méthode virtual de classe de base 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 du même nom dans la base. class et il doit être lié en utilisant le 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).

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top