Différence entre l'observation et la substitution en C #?


100

Quelle est la différence entre l' observation et la substitution d' une méthode en C #?

Réponses:


152

Eh bien l'héritage ...

supposons que vous ayez ces classes:

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

puis quand vous appelez ceci:

A clA = new A();
B clB = new B();

Console.WriteLine(clA.Foo()); // output 5
Console.WriteLine(clA.Bar()); // output 5
Console.WriteLine(clB.Foo()); // output 1
Console.WriteLine(clB.Bar()); // output 1

//now let's cast B to an A class
Console.WriteLine(((A)clB).Foo()); // output 5 <<<-- shadow
Console.WriteLine(((A)clB).Bar()); // output 1

Supposons que vous ayez une classe de base et que vous utilisiez la classe de base dans tout votre code au lieu des classes héritées, et que vous utilisiez shadow, elle renverra les valeurs renvoyées par la classe de base au lieu de suivre l'arbre d'héritage du type réel de l'objet.

Exécutez le code ici

J'espère que j'ai du sens :)


16
Le remplacement fournit le polymorphisme, le shadowing fournit une implémentation différente à ce niveau de la hiérarchie, mais pas de manière polymorphique.
David Rodríguez - dribeas

@dribeas, Quelle définition du polymorphisme utiliseriez-vous pour tirer cette conclusion?
AnthonyWJones

9
@AnthonyWJones, le polymorphisme est la capacité d'un type (dérivé) à être utilisé comme un type (de base) différent où l'implémentation réelle (comportement) est celle du type spécifique (dérivé) réel. Si vous remplacez, la méthode dérivée sera appelée par référence à la base, mais si vous observez ce n'est pas vrai
David Rodríguez - dribeas

2
Il me semble que vous avez une erreur dans votre exemple de code. Le casting devrait être ((A) clB) .Foo (), n'est-ce pas?
trendl

1
Non, car la barre est virtuelle, elle appellera donc toujours la barre B
Stormenet

32

L'observation est en fait un langage VB pour ce que nous appellerions se cacher en C #.

Souvent, le masquage (shadowing en VB) et le remplacement sont affichés comme dans la réponse de Stormenet .

Une méthode virtuelle est remplacée par une sous-classe et les appels à cette méthode même sur le type de super-classe ou à partir du code interne de la super-classe appelleront l'implémentation de remplacement à partir de la sous-classe.

Ensuite, une méthode concrète est affichée (une non marquée comme virtuelle ou abstraite) étant masquée en utilisant le newmot - clé lors de la définition d'une méthode avec une signature identique sur la sous-classe. Dans ce cas, lorsque la méthode est appelée sur le type de super-classe, l'implémentation d'origine est utilisée, la nouvelle implémentation n'est disponible que sur la sous-classe.

Cependant, ce qui manque souvent, c'est qu'il est également possible de cacher une méthode virtuelle.

class A
{
    public virtual void DoStuff() { // original implementation }
}

class B : A
{
    public new void DoStuff() {  //new implementation }
}

B b = new B();
A a = b;

b.DoStuff(); //calls new implementation
a.DoStuff(); //calls original implementation.

Notez que dans l'exemple ci-dessus, DoStuff devient concret et ne peut pas être remplacé. Cependant, il est également possible d'utiliser les mots virtual- newclés et ensemble.

class A
{
    public virtual void DoStuff() { // original implementation }
}

class B : A
{
    public new virtual void DoStuff() {  //new implementation }
}

class C : B
{
    public override void DoStuff() { //replacement implementation }
}

C c = new C();
B b = c;
A a = b;

c.DoStuff(); //calls replacement implementation
b.DoStuff(); //calls replacement implementation
a.DoStuff(); //calls original implementation.

Notez que bien que toutes les méthodes impliquées soient virtuelles, le remplacement sur C n'affecte pas la méthode virtuelle sur A car l'utilisation de newdans B masque l'implémentation A.

Edit: Il a été noté dans les commentaires de cette réponse que ce qui précède peut être dangereux ou du moins pas particulièrement utile. Je dirais que oui, cela peut être dangereux et le serait si cela était utile.

En particulier, vous pourriez avoir toutes sortes de problèmes si vous modifiez également les modificateurs d'accessibilité. Par exemple:-

public class Foo
{
    internal Foo() { }
    protected virtual string Thing() { return "foo"; }
}

public class Bar : Foo
{
 internal new string Thing() { return "bar"; }
}

Pour un héritier externe de Bar, Fool'implémentation de Thing () reste accessible et remplaçable. Tout cela est légal et explicable selon les règles de type .NET, sans jamais être intuitif.

J'ai posté cette réponse pour approfondir une compréhension du fonctionnement des choses et non comme une suggestion de techniques pouvant être utilisées librement.


2
Heureux de le savoir. Bien que son utilisation puisse être dangereuse :)
Stormenet

2
Tous les outils peuvent être dangereux lorsqu'ils ne sont pas utilisés correctement.
AnthonyWJones

1
Mais, sa convivialité semble vraiment discutable! Existe-t-il une application open source `` sérieuse '' qui l'utilise?
Jox

4
Convivialité? Voulez-vous dire utilité? Des choses marginales peuvent sembler inutiles jusqu'à ce que vous en ayez besoin.
AnthonyWJones

Il semble que Shadowing entre en image UNIQUEMENT lors de la lecture virtuelle et nouvelle. @ Stormenet n'explique que la fonction de remplacement car c'est un comportement normal de la classe d'appeler sa propre méthode à moins qu'elle ne soit virtuelle.
Sumit Kapadia

6

Je pense que la principale différence est qu'avec l'ombre, vous réutilisez essentiellement le nom et ignorez simplement l'utilisation de la superclasse. Avec le remplacement, vous modifiez l'implémentation, mais pas l'accessibilité et la signature (par exemple, les types de paramètres et le retour). Voir http://www.geekinterview.com/question_details/19331 .


5

L'observation est un concept VB.NET. En C #, l'ombre est connue sous le nom de masquage. Il masque la méthode de classe dérivée. Il est accompli en utilisant le mot-clé «nouveau».

Le mot clé Override est utilisé pour fournir une implémentation complètement nouvelle d'une méthode de classe de base (qui est marquée «Virtuelle») dans la classe dérivée.


Vous voulez dire. Il masque la méthode de classe dérivée à la place utilise la méthode de classe de base. ?
shaijut

0

En gros, si vous avez quelque chose comme ci-dessous,

Class A
{
}

Class B:A
{
}

A a = new B();

Toute méthode que vous appelez sur l'objet 'a' sera faite sur le type de 'a' (ici le type est 'A') Mais si vous implémentez la même méthode dans la classe B qui est déjà présente dans la classe A, le compilateur va vous avertit d'utiliser un mot-clé "Nouveau". Si vous utilisez "Nouveau", l'avertissement disparaîtra. A part cela, il n'y a aucune différence entre utiliser "Nouveau" ou ne pas l'utiliser dans la classe héritée.

Dans certaines situations, vous devrez peut-être appeler une méthode de la classe de référence que l'instance particulière contient à ce moment au lieu d'appeler une méthode sur le type d'objet. Dans le cas ci-dessus, la référence qu'il contient est «B», mais le type est «A». Donc, si vous voulez que l'appel de méthode se produise sur «B», vous utilisez Virtual et le remplacement pour y parvenir.

J'espère que cela t'aides...

Daniel Sandeep.


0

S'il y a un cas dans lequel vous ne pouvez pas modifier le contenu d'une classe, disons A, mais que vous voulez utiliser ses quelques méthodes avec vous avez une méthode dont le nom est commun, vous pouvez utiliser votre propre implémentation de méthode par le newmot - clé.

Le point crucial est de l'utiliser que la référence et l'objet doivent être du même type.

class A
{
    public void Test()
    {
        Console.WriteLine("base");
    }
}

class B : A
{
    public new void Test()
    {
        Console.WriteLine("sub");
    }

    public static void Main(string[] args)
    {
        A a = new A();
        B aa = new B();
        a.Test();
        aa.Test();
    }
}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.