Domanda

Perché è nuovo / sostituzione necessaria sui metodi astratti ma non su metodi virtuali?

Esempio 1:

abstract class ShapesClass
{
    abstract public int Area(); // abstract!
}

class Square : ShapesClass
{
    int x, y;

    public int Area() // Error: missing 'override' or 'new'
    {
        return x * y;
    }
}

Il compilatore mostrerà questo errore: Per rendere la corrente di override membro che l'attuazione, aggiungere la parola chiave override. In caso contrario, aggiungere la nuova parola chiave

Esempio 2:

class ShapesClass
{
    virtual public int Area() { return 0; } // it is virtual now!
}

class Square : ShapesClass
{
    int x, y;

    public int Area() // no explicit 'override' or 'new' required
    {
        return x * y;
    }
}

Questo compilerà bene, nascondendo il metodo di default.

I comprendere appieno le differenze tecniche. Tuttavia mi chiedo perché il linguaggio è stato progettato in questo modo. Non sarebbe meglio avere la stessa limitazione in "Esempio 2" come bene? Voglio dire nella maggior parte dei casi, se si crea un metodo con lo stesso nome nella classe padre, di solito l'intenzione di ignorare esso. Quindi penso affermando esplicitamente Override / Nuovo avrebbe senso su metodi virtuali.

C'è un motivo di design-saggio per questo comportamento?

Aggiornamento: Il secondo campione provoca in realtà un avvertimento. Il primo campione mostra un errore perché la sottoclasse è necessaria per implementare il metodo astratto. Non ho visto l'avvertimento in VS .. rende perfettamente senso per me ora. Grazie.

È stato utile?

Soluzione

Con l'uso C # 3.0 del compilatore come spedito in .NET 3.5 SP1, o il compilatore C # 4.0 come spedito in .NET 4.0, ottengo il seguente Errore per il primo esempio:

  

Errore CS0534: 'ConsoleApplication3.Square' non implementa ereditato membro astratto 'ConsoleApplication3.ShapesClass.Area ()'

E il seguente Attenzione per la seconda:

  

avviso CS0114: 'ConsoleApplication3.Square.Area ()' pelli membro ereditato 'ConsoleApplication3.ShapesClass.Area ()'. Per rendere la corrente di override membro che l'attuazione, aggiungere la parola chiave override. In caso contrario, aggiungere la nuova parola chiave.

Nel primo caso si tratta di un errore perché non sono in realtà l'override del metodo di base, il che significa che non v'è alcuna implementazione per il metodo astratto in una classe concreta. Nel secondo caso si tratta di un avvertimento, perché il codice è tecnicamente corretta, ma il compilatore sospetta che non è quello che volevi dire. Questo è uno dei motivi per cui è generalmente una buona idea per permettere alle "Avvertenze trattare come gli errori di" impostazione di compilazione.

Quindi non posso repro vostro comportamento e il comportamento degli sguardi compilatore giusto per me. Quale versione del compilatore stai usando?

Altri suggerimenti

Ecco la risposta direttamente dalla C # spec.

  

... si nasconde un nome accessibile da un   ambito ereditato provoca un avvertimento per essere   segnalati. Nell'esempio

class Base
{
    public void F() {}
}
class Derived: Base
{
    public void F() {}      // Warning, hiding an inherited name
}
  

la dichiarazione di F in cause derivate   un avvertimento da segnalare. Nascondere un   nome ereditato non è specificamente un   errore, dal momento che sarebbe precludere   evoluzione separata delle classi di base.   Per esempio, la situazione di cui sopra potrebbe   hanno avvenuto perché un secondo   versione di base ha introdotto un metodo di F   che non era presente in un precedente   versione della classe. Aveva il sopra   situazione stato un errore, allora qualsiasi   modifica apportata a una classe base in un   libreria di classi con versione a parte   potrebbe potenzialmente causare derivato   classi non sono più validi. L'avviso   causata da nascondere un nome di latta ereditato   essere eliminate mediante l'utilizzo del nuovo   modificatore:

class Base
{
    public void F() {}
}
class Derived: Base
{
    new public void F() {}
}
  

Il nuovo modificatore indica che la F   in Derivato è “nuovo”, e che è   anzi destinato a nascondere il ereditata   membro.

La differenza è che il metodo astratto deve essere ignorato, ma il virtuale non è così.

E 'un errore per ereditare la classe astratta (in una classe non astratta) senza implementare tutti i membri astratti, ma si ottiene solo un avviso quando eredita dalla classe senza specificare override o new per il metodo virtuale.

Credo che nel primo modo si ottiene l'errore del compilatore, perché il metodo astratto è nascosto e non implementato (in modo efficace la vostra classe è sbagliato, e sarebbe difficile capire perché). Nel secondo caso si ottiene solo un avvertimento, perché la classe è utilizzabile.

Versioning

A prima vista, si potrebbe pensare che il metodo nascosto non appare particolarmente utile. C'è una situazione dove potrebbe essere necessario usarlo, però. Diciamo che si desidera utilizzare una classe denominata MotorVehicle che è stato scritto da un altro programmatore, e si desidera utilizzare questa classe per derivare la propria classe. Ulteriore, Supponiamo anche che si desidera definire un metodo Accelerate() nella classe derivata. Ad esempio:

public class Car : MotorVehicle
{
    // define the Accelerate() method
    public void Accelerate()
    {
        Console.WriteLine(“In Car Accelerate() method”);
        Console.WriteLine(model + “ accelerating”);
    }
}

Quindi, supponiamo che l'altro programmatore in seguito modifica la classe motoveicolo e decide aggiungere il proprio metodo virtual Accelerate():

public class MotorVehicle
{
    // define the Accelerate() method
    public virtual void Accelerate()
    {
        Console.WriteLine(“In MotorVehicle Accelerate() method”);
        Console.WriteLine(model + “ accelerating”);
    }
}

L'aggiunta di questo metodo Accelerate() dall'altro programmatore causa un problema: il Metodo Accelerate() nelle pelli di classe Car il metodo Accelerate() ereditato adesso definito nel loro classe MotorVehicle. Più tardi, quando si arriva a compilare il codice categoria Car, non è chiaro al compilatore se effettivamente destinato il metodo per nascondere il metodo ereditato. A causa di questo, il compilatore segnala il seguente avviso quando si tenta di compilare la classe auto:

  

avviso CS0114: ‘Car.Accelerate ()’ pelli ereditati membro   ‘MotorVehicle.Accelerate ()’. Per rendere la sostituzione degli attuali che   implementazione, aggiungere la parola chiave override. In caso contrario, aggiungere la nuova parola chiave.

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