Vous vous demandez quelle est la différence entre ce qui suit:
Cas 1: Classe de base
public void DoIt();
Cas 1: Classe héritée
public new void DoIt();
Cas 2: Classe de base
public virtual void DoIt();
Cas 2: Classe héritée
public override void DoIt();
Les cas 1 et 2 semblent avoir le même effet en fonction des tests que j'ai effectués. Y a-t-il une différence ou une manière préférée?
Le modificateur override peut être utilisé sur méthodes virtuelles et doit être utilisé sur méthodes abstraites. Cela indique pour le compilateur à utiliser le dernier défini mise en œuvre d'une méthode. Même si la méthode est appelée sur une référence à la classe de base, il utilisera le la mise en œuvre le dépassant.
public class Base
{
public virtual void DoIt()
{
}
}
public class Derived : Base
{
public override void DoIt()
{
}
}
Base b = new Derived();
b.DoIt(); // Calls Derived.DoIt
appellera Derived.DoIt
si cela remplace Base.DoIt
.
Le nouveau modificateur indique au compilateur pour utiliser votre implémentation de classe enfant au lieu de la classe parente la mise en oeuvre. Tout code qui n'est pas référençant votre classe mais le parent La classe utilisera la classe parente la mise en oeuvre.
public class Base
{
public virtual void DoIt()
{
}
}
public class Derived : Base
{
public new void DoIt()
{
}
}
Base b = new Derived();
Derived d = new Derived();
b.DoIt(); // Calls Base.DoIt
d.DoIt(); // Calls Derived.DoIt
Appelera d'abord Base.DoIt
, puis Derived.DoIt
. Il s’agit en réalité de deux méthodes entièrement distinctes qui portent le même nom, plutôt que la méthode dérivée remplaçant la méthode de base.
Source: Blog Microsoft
virtual : indique qu'une méthode peut être remplacée par un héritier
override : remplace la fonctionnalité d'une méthode virtuelle dans une classe de base, en fournissant des fonctionnalités différentes.
new : masque la méthode d'origine (qui ne doit pas nécessairement être virtuelle), offrant des fonctionnalités différentes. Cela ne devrait être utilisé que si c'est absolument nécessaire.
Lorsque vous masquez une méthode, vous pouvez toujours accéder à la méthode d'origine en transposant vers la classe de base. Ceci est utile dans certains scénarios, mais dangereux.
Dans le premier cas, vous masquez la définition dans la classe parente. Cela signifie qu'il ne sera invoqué que lorsque vous traiterez avec l'objet en tant que classe enfant. Si vous convertissez la classe en son type parent, la méthode du parent sera invoquée. Dans le second cas, la méthode est remplacée et sera appelée, que l'objet soit converti en classe enfant ou mère.
essayez de suivre: (cas1)
((BaseClass)(new InheritedClass())).DoIt()
Edit: virtual + override sont résolus au moment de l'exécution (donc, écrasez les méthodes virtuelles), alors que new crée simplement une nouvelle méthode portant le même nom et masque l'ancien, elle est résolue à la compilation -> votre compilateur appellera la méthode ' voit
La différence entre les deux cas est que, dans le cas 1, la méthode DoIt
de base ne soit pas remplacée, mais masquée. Cela signifie que, selon le type de variable, la méthode appelée sera appelée. Par exemple:
BaseClass instance1 = new SubClass();
instance1.DoIt(); // Calls base class DoIt method
SubClass instance2 = new SubClass();
instance2.DoIt(); // Calls sub class DoIt method
Cela peut être très déroutant et entraîner un comportement imprévu et doit être évité si possible. Donc, la manière préférée serait le cas 2.
Dans le cas 1, si vous avez utilisé la méthode DoIt () de la classe héritée alors que le type est déclaré en tant que classe de base, vous verrez même l'action de la classe de base.
/* Results
Class1
Base1
Class2
Class2
*/
public abstract class Base1
{
public void DoIt() { Console.WriteLine("Base1"); }
}
public class Class1 : Base1
{
public new void DoIt() { Console.WriteLine("Class1"); }
}
public abstract class Base2
{
public virtual void DoIt() { Console.WriteLine("Base2"); }
}
public class Class2 : Base2
{
public override void DoIt() { Console.WriteLine("Class2"); }
}
static void Main(string[] args)
{
var c1 = new Class1();
c1.DoIt();
((Base1)c1).DoIt();
var c2 = new Class2();
c2.DoIt();
((Base2)c2).DoIt();
Console.Read();
}
Ma façon de garder à l'esprit les deux mots clés qu'ils sont opposés l'un à l'autre.
override
: virtual
mot-clé doit être défini pour remplacer la méthode. La méthode utilisant le mot clé override
, quel que soit le type de référence (référence de la classe de base ou de la classe dérivée), si elle est instanciée avec la classe de base, exécute la méthode de la classe de base. Sinon, la méthode de la classe dérivée s'exécute.
new
: si le mot clé est utilisé par une méthode, contrairement au mot clé override
, le type de référence est important. S'il est instancié avec une classe dérivée et que le type de référence est une classe de base, la méthode de la classe de base s'exécute. S'il est instancié avec une classe dérivée et que le type de référence est une classe dérivée, la méthode de la classe dérivée s'exécute. À savoir, il s'agit du contraste du mot clé override
. En passant, si vous oubliez ou omettez d’ajouter un nouveau mot clé à la méthode, le compilateur se comporte par défaut lorsque le mot clé new
est utilisé.
class A
{
public string Foo()
{
return "A";
}
public virtual string Test()
{
return "base test";
}
}
class B: A
{
public new string Foo()
{
return "B";
}
}
class C: B
{
public string Foo()
{
return "C";
}
public override string Test() {
return "derived test";
}
}
Appeler en principal:
A AClass = new B();
Console.WriteLine(AClass.Foo());
B BClass = new B();
Console.WriteLine(BClass.Foo());
B BClassWithC = new C();
Console.WriteLine(BClassWithC.Foo());
Console.WriteLine(AClass.Test());
Console.WriteLine(BClassWithC.Test());
Sortie:
A
B
B
base test
derived test
Parmi tous ceux-ci, new est le plus déroutant. Par le biais d'expérimentations, le nouveau mot-clé revient à donner aux développeurs la possibilité de remplacer l'implémentation de classe héritante par celle de base en définissant explicitement le type. C'est comme si on pensait dans l'autre sens.
Dans l'exemple ci-dessous, le résultat retournera "Résultat dérivé" jusqu'à ce que le type soit explicitement défini comme test BaseClass, puis "Résultat de base" sera renvoyé.
class Program
{
static void Main(string[] args)
{
var test = new DerivedClass();
var result = test.DoSomething();
}
}
class BaseClass
{
public virtual string DoSomething()
{
return "Base result";
}
}
class DerivedClass : BaseClass
{
public new string DoSomething()
{
return "Derived result";
}
}
L'article ci-dessous est dans vb.net mais je pense que l'explication sur les nouveaux remplacements vs est très facile à comprendre.
https://www.codeproject.com/articles/17477/the-dark-shadow-of-overrides
À un moment donné de l'article, il y a cette phrase:
En général, Shadows suppose que la fonction associée au type est invoqué, alors que Overrides suppose que l’implémentation de l’objet est réalisé.
La réponse acceptée à cette question est parfaite, mais je pense que cet article fournit de bons exemples pour mieux comprendre les différences entre ces deux mots clés.
Si le mot clé override
est utilisé dans la classe dérive, il remplace la méthode parent.
Si le mot clé new
est utilisé dans la classe dérive, la méthode dérivée est masquée par la méthode parent.
Dans le premier cas, il appellera la méthode de la classe dérivée DoIt () car le nouveau mot-clé masque la méthode de la classe de base DoIt ().
Dans le second cas, il appellera overriden DoIt ()
public class A
{
public virtual void DoIt()
{
Console.WriteLine("A::DoIt()");
}
}
public class B : A
{
new public void DoIt()
{
Console.WriteLine("B::DoIt()");
}
}
public class C : A
{
public override void DoIt()
{
Console.WriteLine("C::DoIt()");
}
}
laisser créer une instance de ces classes
A instanceA = new A();
B instanceB = new B();
C instanceC = new C();
instanceA.DoIt(); //A::DoIt()
instanceB.DoIt(); //B::DoIt()
instanceC.DoIt(); //B::DoIt()
Tout est attendu au dessus. Laissez set instanceB et instanceC à instanceA et appelez la méthode DoIt () et vérifiez le résultat.
instanceA = instanceB;
instanceA.DoIt(); //A::DoIt() calls DoIt method in class A
instanceA = instanceC;
instanceA.DoIt();//C::DoIt() calls DoIt method in class C because it was overriden in class C
La différence fonctionnelle ne sera pas montrée dans ces tests:
BaseClass bc = new BaseClass();
bc.DoIt();
DerivedClass dc = new DerivedClass();
dc.ShowIt();
Dans cet exemple, le Doit appelé est celui que vous souhaitez appeler.
Pour voir la différence, vous devez faire ceci:
BaseClass obj = new DerivedClass();
obj.DoIt();
Vous verrez si vous exécutez ce test que dans le cas 1 (comme vous l'avez défini), la fonction DoIt()
dans BaseClass
est appelée, dans le cas 2 (selon votre définition), la fonction DoIt()
dans DerivedClass
.
J'avais la même question et c'est très déroutant. Vous devriez considérer que override et new ne fonctionnent qu'avec des objets de type classe de base et valeur de classe dérivée. Dans ce cas seulement, vous verrez l'effet de override et new: Donc, si vous avez class A
et B
, B
hérite de A
, alors vous instancier un objet comme celui-ci:
A a = new B();
Maintenant, sur les méthodes appelantes prendront en compte son état .Override: signifie qu'il étend la fonction de la méthode, puis qu'il utilise la méthode dans la classe dérivée, alors que new indique au compilateur cache la méthode dans la classe dérivée et utilise la méthode dans la classe de base à la place ... Voici un très bon aperçu de ce sujet: