Frage

Das folgende Programm druckt

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

(wie es sein sollte)

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

aber wenn ich Stichwort ‚neue‘ ändern zu ‚überschreiben‘ in Klasse B wie folgt:

    public override void Print(C c)

urplötzlich Programm beginnt zu drucken:

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

Warum?

War es hilfreich?

Lösung

Dies ist mit, wie überladene Methoden zu tun, werden aufgelöst.

Effektiv (vereinfachte etwas), sucht der Compiler zunächst bei der angegebenen Art des Ausdrucks (B) in diesem Fall und sucht nach Kandidaten Methoden , die ersten in dieser Art deklariert werden . Wenn es Methoden gibt, die geeignet sind (das heißt, in der alle Argumente auf die Methode der Parametertypen umgewandelt werden), dann es nicht sehen alle Eltern-Typen. Dies bedeutet, dass überschriebene Verfahren, bei denen die Erstmeldung in einem übergeordneten Typ ist, nicht bekommen, einen Blick in, wenn es irgendwelche „frisch erklärte“ geeignete Methoden in dem abgeleiteten Typ ist.

Hier ist ein etwas einfacheres Beispiel:

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

Diese Derived.Foo(double) druckt - auch wenn die Compiler es wissen, mit einem Parameter vom Typ int ein Matching-Verfahren ist, und das Argument ist int geben, und die Umwandlung von int zu int ist „besser“ als die Umwandlung von int zu double, die Tatsache, dass nur die Foo(double) Methode ursprünglich ist erklärt in Derived bedeutet, dass der Compiler ignoriert Foo(int).

Dies ist IMO sehr überraschend. Ich kann sehen, warum es der Fall wäre, wenn Derived nicht Foo außer Kraft gesetzt hat - sonst eine neue, spezifischere, Methode in der Basisklasse Einführung könnte das Verhalten unerwartet ändern - aber deutlich Derived hier weiß über Base.Foo(int) wie es überschreibt es. Dies ist einer der (relativ wenigen) Stellen, an denen ich die C # Designer die falsche Entscheidung glauben.

Andere Tipps

Ok, also

    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() + ")");
    }

Dies erklärt, ein neues Verfahren für den Druck. Jetzt, da B von A erbt, die Sie anrufen simly die neue Methode zweimal. Wenn Sie die Methode overide, dies ändert dann die Methodensignatur, wenn Sie für einen Anruf, aber wenn man die B Unterschrift nennt, dann hat es seine eigene Methode Signatur.

Ich bin nicht sicher, ob ich erkläre klar, aber gute Frage.

mit neu:

A und B die gleiche Umsetzung der Druckmethode erhalten.

mit Überschreibung:

A eine andere Methode Signatur hat wie nach B, Sie haben die Methode Signatur in B nur in A nicht verändert.

Um die neue Verwendung es im Grunde ignoriert diese:

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

Das war eine große Frage.
Alle Antworten finden Sie hier: http://msdn.microsoft.com/en-us /library/6fawty39(VS.80).aspx

Der Kern ist dies:

  

... der C # -Compiler wird zunächst versuchen, machen   der Anruf kompatibel mit den Versionen   von [functionName-] erklärt ursprünglich auf   [Die abgeleitete Klasse]. Außer Kraft setzen Methoden nicht   gilt als eine Klasse deklariert,   sie sind neue Implementierungen ein   Methode deklariert auf einer Basisklasse. Nur   wenn die C # Compiler kann nicht das Match   Methodenaufruf zu einer ursprünglichen Methode   [Die abgeleitete Klasse] wird es versuchen, den Anruf entsprechen   zu einer überschriebenen Methode mit dem gleichen   Name und kompatible Parameter.

Also, weil Sie haben eine neue Methode Print (I i) auf der abgeleiteten Klasse, die das Argument „c“ übereinstimmt, (weil c implementiert I), das Verfahren hat Vorrang vor der „Überschreibung“ -Methode.

Wenn Sie die Methode als „neu“ markieren, werden sie beide als auf der abgeleiteten Klasse implementiert werden, und der Druck (C c) Verfahren mehr entspricht genau den Parameter „c“, so dass er Vorrang hat.

Das ist mindestens so sehr eine Frage, wie die Methode Überlastung arbeitet in C #. Ich denke, dass Sie eine interessante Situation hier hervorgehoben haben ...

Im ersten Fall (unter Verwendung des new Schlüsselwort für das Verfahren), die Compiler die Print -Methodenüberladung mit dem Parameter vom Typ C zu verwenden, entscheidet, weil es Art ist genau äquivalent zu dem von dem Parameter übergeben (dh keine implizite Konvertierung erforderlich) während einer impliziten Umwandlung in die Schnittstelle I erforderlich wäre, wenn der Compiler die Print Methode wählen sind, die ein Argument vom Typ nimmt. I - mit anderen Worten, es wählt die mehr „offensichtlich“ -Methodenüberladung

Im zweiten Fall (mit dem override Schlüsselwort auf der Methode), entscheidet der Compiler ich die Überlastung von Print mit Parametern des Typs zu verwenden, da, obwohl Sie die Print(C c) -Methodenüberladung in der Klasse B überschreiben, ist es effektiv definiert in die übergeordnete Klasse A, die Print(I i) -Methodenüberladung in der Tat macht die höchste Ebene Überlastung und deshalb die direkte eins, dh des ersten der Compiler findet.

Hoffentlich wird Ihnen helfen, zu verstehen. Lassen Sie mich wissen, ob ich weiter keine Punkte clairfy müssen ...

. Hinweis: Wenn ich falsch zu sagen, dass der Compiler diese Dinge tut, dann bitte korrigieren Sie mich, wenn es im Interesse des Arguments wenig Unterschied macht, ob es die Compiler oder CLR / JIT ist, so scheint es,

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top