Domanda

I seguenti programma stampa

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

(come dovrebbe)

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

Tuttavia, se cambio parola chiave 'nuovo' a 'sostituzione' in classe B in questo modo:

    public override void Print(C c)

tutto un programma tratto inizia a stampare:

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

Perché?

È stato utile?

Soluzione

Questo è quello di fare con il modo metodi di overload vengono risolti.

In effetti (semplificato un po '), il compilatore prima esamina il tipo dichiarato dell'espressione (B), in questo caso e cerca metodi candidati che vengono prima dichiarata in quel tipo . Se ci sono metodi che sono appropriati (cioè in cui tutti gli argomenti possono essere convertiti in tipi di parametri del metodo) allora non un'occhiata a qualsiasi tipo genitore. Questo significa che i metodi sostituiti, in cui la dichiarazione iniziale è in un tipo di genitore, non si ottiene un look-in se ci sono "appena dichiarato" metodi adeguati di tipo derivato.

Ecco un esempio leggermente più semplice:

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

Questo stampa Derived.Foo(double) - anche se il compilatore sa che c'è un metodo di corrispondenza con un parametro di tipo int, e l'argomento è di tipo int, e la conversione da int a int è "migliore" rispetto alla conversione da int a double, il fatto che solo il metodo Foo(double) è originariamente ha dichiarato in Derived significa che il compilatore ignora Foo(int).

Questo è molto sorprendente, IMO. Posso capire perché sarebbe il caso se Derived non ignorare Foo - altrimenti l'introduzione di un nuovo, più specifica, il metodo nella classe base potrebbe cambiare il comportamento in modo imprevisto - ma Derived chiaramente qui sa su Base.Foo(int) come è l'override di esso. Questo è uno dei (relativamente pochi) punti in cui credo che il C # designer preso la decisione sbagliata.

Altri suggerimenti

Ok, quindi

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

Questo dichiara un nuovo metodo per la stampa. Ora, poiché B eredita da A, si sta simly chiamando il nuovo metodo per due volte. Quando si overide il metodo, questo poi cambia la firma del metodo quando si chiama per A, ma quando si chiama la firma B, allora ha una propria firma del metodo.

Non sono sicuro se sto spiegando domanda chiara ma buono.

utilizzando nuova:

A e B ottengono la stessa implementazione del metodo di stampa.

utilizzando Override:

A ha una firma metodo diverso a B come, non hanno cambiato la firma del metodo in B solo in A.

utilizzando il nuovo ignora fondamentalmente questo:

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

Questa è stata una grande domanda.
Tutte le risposte possono essere trovate qui: http://msdn.microsoft.com/en-us /library/6fawty39(VS.80).aspx

Il succo è questo:

  

... il compilatore C # in primo luogo cercare di fare   la chiamata compatibile con le versioni   di [functionName] dichiarato in origine su   [La classe derivata]. metodi di override non sono   considerata come dichiarato su una classe,   sono nuove implementazioni di un   Metodo dichiarato in una classe di base. Solo   se il compilatore C # non può corrispondere al   metodo di chiamata a un metodo originale su   [La classe derivata] si è cercare di abbinare la chiamata   ad un metodo sostituito con lo stesso   nome e parametri compatibili.

Quindi, perché si ha un nuovo metodo di stampa (I i) sulla classe derivata che corrisponde al argomento "c", (perché c implementa I), tale metodo ha la precedenza sul metodo di "override".

Quando si contrassegna il metodo come "nuovo", sono entrambi considerati da attuare sulla classe derivata, e (c C) Metodo di stampa più si avvicina al parametro "c", quindi ha la precedenza.

Questo è almeno quanto una domanda su come metodo di sovraccarico lavora in C #. Credo che tu abbia evidenziato una situazione interessante qui ...

Nel primo caso (utilizzando la parola chiave new sul metodo), il compilatore decide di utilizzare l'overload metodo Print con il parametro di tipo C perché è tipo è esattamente equivalente a quello del parametro passato (cioè senza conversione implicita è richiesta), mentre una conversione implicita per l'interfaccia di I sarebbe necessaria se il compilatore dovesse scegliere il metodo Print che prende un argomento di tipo I -. in altre parole, si sceglie il metodo più sovraccarico "ovvio"

Nel secondo caso (utilizzando la parola chiave override sul metodo), il compilatore decide di utilizzare il sovraccarico di Print con il parametro di tipo I, perché anche se si sta eseguendo l'override del overload del metodo Print(C c) nella classe B, è effettivamente definito in la classe principale a, rendendo il metodo overload Print(I i) infatti sovraccarico di livello più alto, e quindi il più diretto, cioè prima il compilatore trova.

Speriamo che questo vi aiuterà a capire. Fatemi sapere se ho bisogno di clairfy ulteriormente i punti di ...

. Nota: Se mi sbaglio di dire che il compilatore fa queste cose, allora per favore mi corregga, ma fa poca differenza per il bene della discussione se è il compilatore o CLR / JIT, sembrerebbe

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top