Question

Les programme suivant

A:C(A,B)
B:C(A,B)

(comme il se doit)

public interface I
{
    string A();
}

public class C : I
{
    public string A()
    {
        return "A";
    }

    public string B()
    {
        return "B";
    }
}

public class A
{
    public virtual void Print(C c)
    {
        Console.WriteLine("A:C(" + c.A() + "," + c.B() + ")");
    }
}

public class B : A
{
    public new void Print(C c)
    {
        Console.WriteLine("B:C(" + c.A() + "," + c.B() + ")");
    }

    public void Print(I i)
    {
        Console.WriteLine("B:I(" + i.A() + ")");
    }
}

class Program
{
    public static void Main(string[] args)
    {
        A a = new A();
        B b = new B();
        C c = new C();
        a.Print(c);
        b.Print(c);
    }
}

Cependant, si je change mot-clé « nouveau » à « remplacement » de la classe B comme ceci:

    public override void Print(C c)

tout d'un programme commence soudain à imprimer:

A:C(A,B)
B:I(A)

Pourquoi?

Était-ce utile?

La solution

Il est à la façon dont les méthodes surchargées sont résolus.

En effet (simplifié un peu), le compilateur regarde d'abord le type déclaré de l'expression (B) dans ce cas et recherche des méthodes candidats qui sont d'abord déclaré dans ce type . S'il y a des méthodes qui sont appropriées (à savoir où tous les arguments peuvent être convertis en les types de paramètres de la méthode) puis ne pas regardez tous les types de parents. Cela signifie que les méthodes surchargées, où la déclaration initiale est dans un type de parent, ne reçoivent pas un look s'il y a des méthodes appropriées « fraîchement déclarées » dans le type dérivé.

Voici un exemple un peu plus simple:

using System;

class Base
{
    public virtual void Foo(int x)
    {
        Console.WriteLine("Base.Foo(int)");
    }
}

class Derived : Base
{
    public override void Foo(int x)
    {
        Console.WriteLine("Derived.Foo(int)");
    }

    public void Foo(double d)
    {
        Console.WriteLine("Derived.Foo(double)");
    }
}

class Test
{
    static void Main()
    {
        Derived d = new Derived();
        d.Foo(10);
    }
}

imprime Derived.Foo(double) - même si le compilateur sait qu'il existe une méthode de mise en correspondance avec un paramètre de type int, et l'argument est de type int, et la conversion de int à int est « meilleure » que la conversion de int à double, le fait que seule la méthode de Foo(double) est à l'origine a déclaré Derived signifie que le compilateur ignore Foo(int).

Il est très surprenant de l'OMI. Je peux voir pourquoi ce serait le cas si Derived ne l'emportait pas sur Foo - l'introduction d'ailleurs une nouvelle version plus spécifique, méthode dans la classe de base pourrait changer le comportement inattendu - mais clairement Derived ici sait à propos Base.Foo(int) comme il est primordial qu'elle. Ceci est l'un des points (relativement peu) où je crois que les concepteurs de C # pris la mauvaise décision.

Autres conseils

Ok, donc

    public new void Print(C c)
    {
        Console.WriteLine("B:C(" + c.A() + "," + c.B() + ")");
    }

    public void Print(I i)
    {
        Console.WriteLine("B:I(" + i.A() + ")");
    }

déclare une nouvelle méthode pour l'impression. Maintenant, parce que B hérite de A, vous appelez simly la nouvelle méthode à deux reprises. Lorsque vous OVERIDE la méthode, cela change alors la signature de la méthode lorsque vous appelez A, mais quand vous appelez la signature B, il a sa propre signature de la méthode.

Je ne sais pas si je suis clair, mais expliquais bonne question.

en utilisant les nouvelles:

A et B reçoivent la même mise en œuvre de la méthode d'impression.

en utilisant override:

A a une signature de méthode différente à B que, vous n'avez pas changé la signature de la méthode en B uniquement dans A.

en utilisant la nouvelle, il ne tient pas compte essentiellement ceci:

    public void Print(I i)
    {
        Console.WriteLine("B:I(" + i.A() + ")");
    }

Ce fut une grande question.
Toutes les réponses se trouvent ici: http://msdn.microsoft.com/en-us /library/6fawty39(VS.80).aspx

L'essentiel de c'est ceci:

  

... le compilateur C # va d'abord essayer de faire   l'appel compatible avec les versions   de [functionName] a déclaré à l'origine sur   [La classe dérivée]. méthodes Override ne sont pas   considéré comme déclaré sur une classe,   ils sont de nouvelles implémentations d'un   Procédé déclaré sur une classe de base. Seulement   si le compilateur C # ne peut pas correspondre à la   appel de méthode à une méthode originale   [La classe dérivée] il va essayer de faire correspondre l'appel   à une méthode substituée avec le même   nom et les paramètres compatibles.

parce que vous avez une nouvelle méthode d'impression (I i) sur la classe dérivée qui correspond à l'argument « c », (parce que c implémente I), cette méthode a la priorité sur la méthode « prioritaire ».

Lorsque vous marquez la méthode comme « nouvelle », ils sont tous deux considérés comme mis en œuvre sur la classe dérivée, et l'impression (C c) méthode correspond plus étroitement le paramètre « c », il a la priorité.

Ceci est au moins autant une question sur la façon dont la méthode surcharge fonctionne en C #. Je pense que vous avez mis en évidence une situation intéressante ici ...

Dans le premier cas (en utilisant le mot-clé new sur la méthode), le compilateur décide d'utiliser la surcharge de méthode Print avec le paramètre de type C, car il est le type est exactement équivalent à celui du paramètre passé (pas de conversion implicite est nécessaire) alors qu'une conversion implicite à l'interface I serait nécessaire si le compilateur devait choisir la méthode de Print qui prend un argument de type I -. autrement dit, il choisit la surcharge plus la méthode « évidente »

Dans le second cas (en utilisant le mot-clé override sur la méthode), le compilateur décide d'utiliser la surcharge de Print avec le paramètre de type I parce que même si vous surchargez la surcharge de méthode Print(C c) dans la classe B, il est effectivement défini dans la classe parent A, ce qui rend la surcharge de la méthode de Print(I i) en fait, la surcharge de plus haut niveau et par conséquent la plus directe, à savoir le premier compilateur trouve.

Espérons que cela vous aidera à comprendre. Permettez-moi de savoir si je dois clairfy des points plus loin ...

Note:. Si je me trompe en disant que le compilateur fait ces choses, alors s'il vous plaît me corriger, mais il fait peu de différence pour le bien de l'argument que ce soit le compilateur ou CLR / JIT, il semblerait

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