Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
In C# un metodo in una classe derivata può avere lo stesso nome di un metodo nella classe base. È possibile specificare il modo in cui i metodi interagiscono usando le parole chiave new e override . Il override
modificatore estende il metodo della classe virtual
base e il new
modificatore nasconde un metodo di classe base accessibile. La differenza è illustrata negli esempi di questo argomento.
In un'applicazione console, dichiarare le seguenti due classi, BaseClass
e DerivedClass
.
DerivedClass
eredita da BaseClass
.
class BaseClass
{
public void Method1()
{
Console.WriteLine("Base - Method1");
}
}
class DerivedClass : BaseClass
{
public void Method2()
{
Console.WriteLine("Derived - Method2");
}
}
Main
Nel metodo dichiarare le variabili bc
, dc
e bcdc
.
bc
è di tipoBaseClass
e il relativo valore è di tipoBaseClass
.dc
è di tipoDerivedClass
e il relativo valore è di tipoDerivedClass
.bcdc
è di tipoBaseClass
e il relativo valore è di tipoDerivedClass
. Si tratta della variabile a cui prestare attenzione.
Poiché bc
e bcdc
hanno tipo BaseClass
, possono accedere direttamente solo a Method1
, a meno che non si usi il cast. La variabile dc
può accedere sia Method1
che Method2
. Queste relazioni sono illustrate nel codice seguente.
class Program
{
static void Main(string[] args)
{
BaseClass bc = new BaseClass();
DerivedClass dc = new DerivedClass();
BaseClass bcdc = new DerivedClass();
bc.Method1();
dc.Method1();
dc.Method2();
bcdc.Method1();
}
// Output:
// Base - Method1
// Base - Method1
// Derived - Method2
// Base - Method1
}
Aggiungere quindi il metodo seguente Method2
a BaseClass
. La firma di questo metodo corrisponde alla firma del Method2
metodo in DerivedClass
.
public void Method2()
{
Console.WriteLine("Base - Method2");
}
Poiché BaseClass
ora include un Method2
metodo, è possibile aggiungere una seconda istruzione chiamante per BaseClass
le variabili bc
e bcdc
, come illustrato nel codice seguente.
bc.Method1();
bc.Method2();
dc.Method1();
dc.Method2();
bcdc.Method1();
bcdc.Method2();
Quando si compila il progetto, si noterà che l'aggiunta del Method2
metodo in BaseClass
genera un avviso. L'avviso indica che il Method2
metodo in DerivedClass
nasconde il Method2
metodo in BaseClass
. È consigliabile usare la new
parola chiave nella Method2
definizione se si intende causare tale risultato. In alternativa, è possibile rinominare uno dei Method2
metodi per risolvere l'avviso, ma questo non è sempre pratico.
Prima di aggiungere new
, eseguire il programma per visualizzare l'output prodotto dalle istruzioni chiamanti aggiuntive. Vengono visualizzati i risultati seguenti.
// Output:
// Base - Method1
// Base - Method2
// Base - Method1
// Derived - Method2
// Base - Method1
// Base - Method2
La new
parola chiave mantiene le relazioni che producono tale output, ma elimina l'avviso. Le variabili con tipo BaseClass
continuano ad accedere ai membri di BaseClass
e la variabile con tipo DerivedClass
continua ad accedere ai membri in DerivedClass
primo luogo e quindi a considerare i membri ereditati da BaseClass
.
Per eliminare l'avviso, aggiungere il new
modificatore alla definizione di Method2
in DerivedClass
, come illustrato nel codice seguente. Il modificatore può essere aggiunto prima o dopo public
.
public new void Method2()
{
Console.WriteLine("Derived - Method2");
}
Eseguire di nuovo il programma per verificare che l'output non sia stato modificato. Verificare anche che l'avviso non venga più visualizzato. Utilizzando new
, stai affermando di essere consapevole che il membro che viene modificato nasconde un membro ereditato dalla classe di base. Per ulteriori informazioni su nascondere il nome tramite ereditarietà, vedere new Modifier.
Per mettere a confronto questo comportamento con gli effetti dell'utilizzo di override
, aggiungere il seguente metodo a DerivedClass
. Il override
modificatore può essere aggiunto prima o dopo public
.
public override void Method1()
{
Console.WriteLine("Derived - Method1");
}
Aggiungere il virtual
modificatore alla definizione di Method1
in BaseClass
. Il virtual
modificatore può essere aggiunto prima o dopo public
.
public virtual void Method1()
{
Console.WriteLine("Base - Method1");
}
Eseguire di nuovo il progetto. Si noti in particolare le ultime due righe dell'output seguente.
// Output:
// Base - Method1
// Base - Method2
// Derived - Method1
// Derived - Method2
// Derived - Method1
// Base - Method2
L'uso del override
modificatore consente di bcdc
accedere al Method1
metodo definito in DerivedClass
. In genere, si tratta del comportamento desiderato nelle gerarchie di ereditarietà. Si desidera che gli oggetti con valori creati dalla classe derivata usino i metodi definiti nella classe derivata. Per ottenere tale comportamento, usa override
per estendere il metodo della classe base.
Il codice seguente contiene l'esempio completo.
using System;
using System.Text;
namespace OverrideAndNew
{
class Program
{
static void Main(string[] args)
{
BaseClass bc = new BaseClass();
DerivedClass dc = new DerivedClass();
BaseClass bcdc = new DerivedClass();
// The following two calls do what you would expect. They call
// the methods that are defined in BaseClass.
bc.Method1();
bc.Method2();
// Output:
// Base - Method1
// Base - Method2
// The following two calls do what you would expect. They call
// the methods that are defined in DerivedClass.
dc.Method1();
dc.Method2();
// Output:
// Derived - Method1
// Derived - Method2
// The following two calls produce different results, depending
// on whether override (Method1) or new (Method2) is used.
bcdc.Method1();
bcdc.Method2();
// Output:
// Derived - Method1
// Base - Method2
}
}
class BaseClass
{
public virtual void Method1()
{
Console.WriteLine("Base - Method1");
}
public virtual void Method2()
{
Console.WriteLine("Base - Method2");
}
}
class DerivedClass : BaseClass
{
public override void Method1()
{
Console.WriteLine("Derived - Method1");
}
public new void Method2()
{
Console.WriteLine("Derived - Method2");
}
}
}
Nell'esempio seguente viene illustrato un comportamento simile in un contesto diverso. L'esempio definisce tre classi: una classe base denominata Car
e due classi derivate da essa ConvertibleCar
e Minivan
. La classe base contiene un DescribeCar
metodo . Il metodo visualizza una descrizione di base di un'auto e quindi chiama ShowDetails
per fornire informazioni aggiuntive. Ognuna delle tre classi definisce un ShowDetails
metodo. Il new
modificatore viene usato per definire ShowDetails
nella ConvertibleCar
classe . Il override
modificatore viene usato per definire ShowDetails
nella Minivan
classe .
// Define the base class, Car. The class defines two methods,
// DescribeCar and ShowDetails. DescribeCar calls ShowDetails, and each derived
// class also defines a ShowDetails method. The example tests which version of
// ShowDetails is selected, the base class method or the derived class method.
class Car
{
public void DescribeCar()
{
System.Console.WriteLine("Four wheels and an engine.");
ShowDetails();
}
public virtual void ShowDetails()
{
System.Console.WriteLine("Standard transportation.");
}
}
// Define the derived classes.
// Class ConvertibleCar uses the new modifier to acknowledge that ShowDetails
// hides the base class method.
class ConvertibleCar : Car
{
public new void ShowDetails()
{
System.Console.WriteLine("A roof that opens up.");
}
}
// Class Minivan uses the override modifier to specify that ShowDetails
// extends the base class method.
class Minivan : Car
{
public override void ShowDetails()
{
System.Console.WriteLine("Carries seven people.");
}
}
L'esempio testa quale versione di ShowDetails
viene chiamata. Il metodo seguente, TestCars1
, dichiara un'istanza di ogni classe e quindi chiama DescribeCar
in ogni istanza.
public static void TestCars1()
{
System.Console.WriteLine("\nTestCars1");
System.Console.WriteLine("----------");
Car car1 = new Car();
car1.DescribeCar();
System.Console.WriteLine("----------");
// Notice the output from this test case. The new modifier is
// used in the definition of ShowDetails in the ConvertibleCar
// class.
ConvertibleCar car2 = new ConvertibleCar();
car2.DescribeCar();
System.Console.WriteLine("----------");
Minivan car3 = new Minivan();
car3.DescribeCar();
System.Console.WriteLine("----------");
}
TestCars1
produce l'output seguente. Si noti in particolare i risultati per car2
, che probabilmente non sono quello previsto. Il tipo dell'oggetto è ConvertibleCar
, ma DescribeCar
non accede alla versione di ShowDetails
definita nella ConvertibleCar
classe perché tale metodo viene dichiarato con il new
modificatore, non con il override
modificatore. Di conseguenza, un ConvertibleCar
oggetto visualizza la stessa descrizione di un Car
oggetto . Confrontare i risultati per car3
, ovvero un Minivan
oggetto . In questo caso, il metodo ShowDetails
dichiarato nella classe Minivan
sovrascrive il metodo ShowDetails
dichiarato nella classe Car
, e la descrizione visualizzata descrive un minivan.
// TestCars1
// ----------
// Four wheels and an engine.
// Standard transportation.
// ----------
// Four wheels and an engine.
// Standard transportation.
// ----------
// Four wheels and an engine.
// Carries seven people.
// ----------
TestCars2
crea un elenco di oggetti con tipo Car
. I valori degli oggetti sono istanziati dalle classi Car
, ConvertibleCar
e Minivan
.
DescribeCar
viene invocato per ogni elemento dell'elenco. Il codice seguente illustra la definizione di TestCars2
.
public static void TestCars2()
{
System.Console.WriteLine("\nTestCars2");
System.Console.WriteLine("----------");
var cars = new List<Car> { new Car(), new ConvertibleCar(),
new Minivan() };
foreach (var car in cars)
{
car.DescribeCar();
System.Console.WriteLine("----------");
}
}
Viene visualizzato l'output seguente. Si noti che è uguale all'output visualizzato da TestCars1
. Il ShowDetails
metodo della ConvertibleCar
classe non viene chiamato, indipendentemente dal fatto che il tipo dell'oggetto sia ConvertibleCar
, come in TestCars1
o Car
, come in TestCars2
. Viceversa, car3
chiama il ShowDetails
metodo dalla Minivan
classe in entrambi i casi, indipendentemente dal tipo Minivan
o dal tipo Car
.
// TestCars2
// ----------
// Four wheels and an engine.
// Standard transportation.
// ----------
// Four wheels and an engine.
// Standard transportation.
// ----------
// Four wheels and an engine.
// Carries seven people.
// ----------
I metodi TestCars3
e TestCars4
completano l'esempio. Questi metodi chiamano ShowDetails
direttamente, prima dagli oggetti aventi tipo ConvertibleCar
e Minivan
(TestCars3
), quindi dagli oggetti aventi tipo Car
(TestCars4
). Il codice seguente definisce questi due metodi.
public static void TestCars3()
{
System.Console.WriteLine("\nTestCars3");
System.Console.WriteLine("----------");
ConvertibleCar car2 = new ConvertibleCar();
Minivan car3 = new Minivan();
car2.ShowDetails();
car3.ShowDetails();
}
public static void TestCars4()
{
System.Console.WriteLine("\nTestCars4");
System.Console.WriteLine("----------");
Car car2 = new ConvertibleCar();
Car car3 = new Minivan();
car2.ShowDetails();
car3.ShowDetails();
}
I metodi producono l'output seguente, che corrisponde ai risultati del primo esempio in questo argomento.
// TestCars3
// ----------
// A roof that opens up.
// Carries seven people.
// TestCars4
// ----------
// Standard transportation.
// Carries seven people.
Il codice seguente mostra il progetto completo e il relativo output.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace OverrideAndNew2
{
class Program
{
static void Main(string[] args)
{
// Declare objects of the derived classes and test which version
// of ShowDetails is run, base or derived.
TestCars1();
// Declare objects of the base class, instantiated with the
// derived classes, and repeat the tests.
TestCars2();
// Declare objects of the derived classes and call ShowDetails
// directly.
TestCars3();
// Declare objects of the base class, instantiated with the
// derived classes, and repeat the tests.
TestCars4();
}
public static void TestCars1()
{
System.Console.WriteLine("\nTestCars1");
System.Console.WriteLine("----------");
Car car1 = new Car();
car1.DescribeCar();
System.Console.WriteLine("----------");
// Notice the output from this test case. The new modifier is
// used in the definition of ShowDetails in the ConvertibleCar
// class.
ConvertibleCar car2 = new ConvertibleCar();
car2.DescribeCar();
System.Console.WriteLine("----------");
Minivan car3 = new Minivan();
car3.DescribeCar();
System.Console.WriteLine("----------");
}
// Output:
// TestCars1
// ----------
// Four wheels and an engine.
// Standard transportation.
// ----------
// Four wheels and an engine.
// Standard transportation.
// ----------
// Four wheels and an engine.
// Carries seven people.
// ----------
public static void TestCars2()
{
System.Console.WriteLine("\nTestCars2");
System.Console.WriteLine("----------");
var cars = new List<Car> { new Car(), new ConvertibleCar(),
new Minivan() };
foreach (var car in cars)
{
car.DescribeCar();
System.Console.WriteLine("----------");
}
}
// Output:
// TestCars2
// ----------
// Four wheels and an engine.
// Standard transportation.
// ----------
// Four wheels and an engine.
// Standard transportation.
// ----------
// Four wheels and an engine.
// Carries seven people.
// ----------
public static void TestCars3()
{
System.Console.WriteLine("\nTestCars3");
System.Console.WriteLine("----------");
ConvertibleCar car2 = new ConvertibleCar();
Minivan car3 = new Minivan();
car2.ShowDetails();
car3.ShowDetails();
}
// Output:
// TestCars3
// ----------
// A roof that opens up.
// Carries seven people.
public static void TestCars4()
{
System.Console.WriteLine("\nTestCars4");
System.Console.WriteLine("----------");
Car car2 = new ConvertibleCar();
Car car3 = new Minivan();
car2.ShowDetails();
car3.ShowDetails();
}
// Output:
// TestCars4
// ----------
// Standard transportation.
// Carries seven people.
}
// Define the base class, Car. The class defines two virtual methods,
// DescribeCar and ShowDetails. DescribeCar calls ShowDetails, and each derived
// class also defines a ShowDetails method. The example tests which version of
// ShowDetails is used, the base class method or the derived class method.
class Car
{
public virtual void DescribeCar()
{
System.Console.WriteLine("Four wheels and an engine.");
ShowDetails();
}
public virtual void ShowDetails()
{
System.Console.WriteLine("Standard transportation.");
}
}
// Define the derived classes.
// Class ConvertibleCar uses the new modifier to acknowledge that ShowDetails
// hides the base class method.
class ConvertibleCar : Car
{
public new void ShowDetails()
{
System.Console.WriteLine("A roof that opens up.");
}
}
// Class Minivan uses the override modifier to specify that ShowDetails
// extends the base class method.
class Minivan : Car
{
public override void ShowDetails()
{
System.Console.WriteLine("Carries seven people.");
}
}
}