8
votes

Les méthodes polymorphes ne fonctionnent pas sur C # 4

Je suis tombé sur un problème très intéressant. Donner le code suivant:

using System;

class Program
{
    class A { }
    class B : A { }

    private static void MyMethod(A a) /* first method */
    {
        Console.WriteLine("A"); ;
    }

    private static void MyMethod(B b) /* second method */
    {
        Console.WriteLine("B");
    }

    static void Main(string[] args)
    {
        var a = new A();
        // Call first method
        MyMethod(a);

        A b = new B();
        // Should call the second method
        MyMethod(b);

        Console.ReadLine();
    }
}


1 commentaires

Ce n'est pas un polymorphisme, vous avez deux instances surchargées de la même méthode, chacune prenant différents types de paramètres. Ensuite, vous déclarez "B" comme A. Le compilateur vous permet de le faire car B hérite A.


3 Réponses :


14
votes

Ce n'est pas un exemple de polymorphisme du tout. Le polymorphisme entre en jeu lorsque vous appelez des méthodes sur l'objet, pas lorsque l'objet est utilisé comme paramètre. Ceci est juste un exemple simple de surcharge de la méthode.

Vous avez déclaré B comme étant de type A, le compilateur va donc créer un lien vers la surcharge qui utilise le type A. Le linker ne se soucie pas que B est une sous-classe d'un , il choisit simplement la surcharge avec la signature la plus proche des types déclarés (pas les types réels) des paramètres passés. p>

Si vous souhaitez forcer à utiliser la 2e méthode, lancez B en TPI B Dans l'appel de méthode. P>

MyMethod((B)b);


5 commentaires

En effet. La même chose se passe dans Java. Comportement prévisible.


Dans une situation plus complexe, la coulée ferait simplement le code laid. Quoi qu'il en soit, je m'attendrais à ce que la lieur se souciait du type de paramètre et d'utiliser la reliure tardive à la place.


Si vous voulez qu'il se comporte de cette façon, vous devez mettre le dosomething SUB sur A et le remplacer dans B . Ensuite, lorsque vous appelez b.dosomething () , il choisira la bonne base sur le type actuel.


Je ferais cela, mais le problème sera que je devrai créer une classe avec une seule méthode pour chaque surcharge.


Cela pourrait indiquer qu'il y a une faiblesse quelque part dans votre conception de candidature. N'oubliez pas que le mot-clé dynamique que vous avez sélectionné car la réponse n'a été effectuée que récemment disponible en C #. Dans les versions antérieures, ce n'était pas une option. Il devrait y avoir des modèles de conception bien établis qui pourraient être capables de résoudre votre problème particulier plus proprement sans recourir à la reliure tardive.



0
votes

Il ne faut pas appeler la deuxième méthode car la référence à B est de type A . Tandis que B contient une référence à une instance de B , qui n'est pas un type réel de B , de sorte que la surcharge utilise un Une référence est choisie.


3 commentaires

Je comprends exactement ce que ça fait, je ne comprends tout simplement pas pourquoi.


Les appels de méthode sont résolus au moment de la compilation. ( Dynamic Types 'Méthodes exclues) C'est pourquoi.


@Tibi: c'est faux. Les méthodes dynamiques sont résolues au moment de l'exécution, les méthodes statiques sont résolues au moment de la compilation. Le polymorphisme n'a rien à voir avec la résolution statique par rapport à la résolution dynamique. En plus de cela, les méthodes ne sont pas polymorphes à moins qu'elles ne soient définies sur le membre. C'est la surcharge de la méthode, pas le polymorphisme.



6
votes

La surcharge de la méthode en C #, par défaut, est déterminée de manière statique à la compilation. Puisque vous passez une variable de type A statiquement typée, elle se liera statiquement à la méthode avec la surcharge. Utilisez le mot-clé dynamique pour obtenir le comportement souhaité. XXX


3 commentaires

Je n'y pensais pas! Merci.


En fait, je ne savais en fait que le mot clé dynamique provoque des appels sur des méthodes surchargées à résoudre au moment de l'exécution. Ceci est pratique à savoir. Je suis curieux quant aux problèmes de performance potentiels avec ce type de reliure tardive cependant.


Je suppose que vous encouragerez quelques performances hits la première fois que vous l'appelez avec un nouveau type de paramètre, car elle doit être résolue, mais est en cache de la CACHED par le DLR.