Weten wanneer u onderdrukking en nieuwe trefwoorden moet gebruiken (C#-programmeerhandleiding)
In C# kan een methode in een afgeleide klasse dezelfde naam hebben als een methode in de basisklasse. U kunt opgeven hoe de methoden communiceren met behulp van de nieuwe trefwoorden en trefwoorden overschrijven . De override
modifier breidt de basisklassemethode virtual
uit en de new
modifier verbergt een toegankelijke basisklassemethode. Het verschil wordt geïllustreerd in de voorbeelden in dit onderwerp.
Declareer in een consoletoepassing de volgende twee klassen en BaseClass
DerivedClass
. DerivedClass
neemt over van BaseClass
.
class BaseClass
{
public void Method1()
{
Console.WriteLine("Base - Method1");
}
}
class DerivedClass : BaseClass
{
public void Method2()
{
Console.WriteLine("Derived - Method2");
}
}
Declareer variabelen bc
in de Main
methode , dc
en bcdc
.
bc
is van het typeBaseClass
en de waarde is van het typeBaseClass
.dc
is van het typeDerivedClass
en de waarde is van het typeDerivedClass
.bcdc
is van het typeBaseClass
en de waarde is van het typeDerivedClass
. Dit is de variabele waar u aandacht aan moet besteden.
Omdat bc
ze bcdc
type hebben BaseClass
, hebben ze alleen rechtstreeks toegang Method1
, tenzij je cast gebruikt. Variabele dc
heeft toegang tot zowel Method2
Method1
als . Deze relaties worden weergegeven in de volgende code.
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
}
Voeg vervolgens de volgende Method2
methode toe aan BaseClass
. De handtekening van deze methode komt overeen met de handtekening van de Method2
methode in DerivedClass
.
public void Method2()
{
Console.WriteLine("Base - Method2");
}
Omdat BaseClass
er nu een Method2
methode is, kan er een tweede aanroepinstructie worden toegevoegd voor BaseClass
variabelen bc
en bcdc
, zoals wordt weergegeven in de volgende code.
bc.Method1();
bc.Method2();
dc.Method1();
dc.Method2();
bcdc.Method1();
bcdc.Method2();
Wanneer u het project bouwt, ziet u dat de toevoeging van de Method2
methode een BaseClass
waarschuwing veroorzaakt. De waarschuwing geeft aan dat de Method2
methode in DerivedClass
de Method2
methode wordt verborgen in BaseClass
. U wordt aangeraden het new
trefwoord in de Method2
definitie te gebruiken als u dat resultaat wilt veroorzaken. U kunt ook de naam van een van de Method2
methoden wijzigen om de waarschuwing op te lossen, maar dat is niet altijd praktisch.
Voordat u het toevoegt new
, voert u het programma uit om de uitvoer te zien die is geproduceerd door de aanvullende aanroepende instructies. De volgende resultaten worden weergegeven.
// Output:
// Base - Method1
// Base - Method2
// Base - Method1
// Derived - Method2
// Base - Method1
// Base - Method2
Het new
trefwoord behoudt de relaties die die uitvoer produceren, maar onderdrukt de waarschuwing. De variabelen met het type BaseClass
blijven toegang krijgen tot de leden van BaseClass
en de variabele die het type DerivedClass
heeft, blijft eerst toegang krijgen tot leden DerivedClass
en vervolgens om leden te overwegen die zijn overgenomen van BaseClass
.
Als u de waarschuwing wilt onderdrukken, voegt u de new
wijziging toe aan de definitie van Method2
in DerivedClass
, zoals wordt weergegeven in de volgende code. De wijzigingsfunctie kan vóór of na public
worden toegevoegd.
public new void Method2()
{
Console.WriteLine("Derived - Method2");
}
Voer het programma opnieuw uit om te controleren of de uitvoer niet is gewijzigd. Controleer ook of de waarschuwing niet meer wordt weergegeven. Door te gebruiken new
, bevestigt u dat u weet dat het lid dat wordt gewijzigd, een lid verbergt dat is overgenomen van de basisklasse. Zie de nieuwe wijzigingsfunctie voor meer informatie over het verbergen van namen via overname.
Als u dit gedrag wilt contrasteren met de effecten van het gebruik override
, voegt u de volgende methode toe aan DerivedClass
. De override
wijzigingsfunctie kan vóór of na public
worden toegevoegd.
public override void Method1()
{
Console.WriteLine("Derived - Method1");
}
Voeg de virtual
wijzigingsfunctie toe aan de definitie van Method1
in BaseClass
. De virtual
wijzigingsfunctie kan vóór of na public
worden toegevoegd.
public virtual void Method1()
{
Console.WriteLine("Base - Method1");
}
Voer het project opnieuw uit. Let vooral op de laatste twee regels van de volgende uitvoer.
// Output:
// Base - Method1
// Base - Method2
// Derived - Method1
// Derived - Method2
// Derived - Method1
// Base - Method2
Het gebruik van de override
modifier maakt bcdc
het mogelijk om toegang te krijgen tot de Method1
methode die is gedefinieerd in DerivedClass
. Dit is doorgaans het gewenste gedrag in overnamehiërarchieën. U wilt dat objecten met waarden die zijn gemaakt op basis van de afgeleide klasse, gebruikmaken van de methoden die zijn gedefinieerd in de afgeleide klasse. U bereikt dit gedrag door de override
basisklassemethode uit te breiden.
De volgende code bevat het volledige voorbeeld.
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");
}
}
}
In het volgende voorbeeld ziet u een vergelijkbaar gedrag in een andere context. In het voorbeeld worden drie klassen gedefinieerd: een basisklasse met de naam Car
en twee klassen die ermee zijn afgeleid, ConvertibleCar
en Minivan
. De basisklasse bevat een DescribeCar
methode. De methode geeft een basisbeschrijving van een auto weer en roept ShowDetails
vervolgens aan om aanvullende informatie op te geven. Elk van de drie klassen definieert een ShowDetails
methode. De new
wijzigingsfunctie wordt gebruikt om in de ConvertibleCar
klasse te definiërenShowDetails
. De override
wijzigingsfunctie wordt gebruikt om in de Minivan
klasse te definiërenShowDetails
.
// 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.");
}
}
In het voorbeeld wordt getest welke versie wordt ShowDetails
aangeroepen. Met de volgende methode TestCars1
declareert u een exemplaar van elke klasse en roept DescribeCar
u vervolgens elk exemplaar aan.
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
produceert de volgende uitvoer. Let vooral op de resultaten, car2
die waarschijnlijk niet zijn wat u had verwacht. Het type van het object is ConvertibleCar
, maar DescribeCar
heeft geen toegang tot de versie van ShowDetails
die versie die in de ConvertibleCar
klasse is gedefinieerd, omdat die methode wordt gedeclareerd met de new
modifier, niet de override
modifier. Als gevolg hiervan geeft een ConvertibleCar
object dezelfde beschrijving weer als een Car
object. Vergelijk de resultaten voor car3
, een Minivan
object. In dit geval overschrijft de ShowDetails
methode die in de Minivan
klasse wordt gedeclareerd de ShowDetails
methode die in de Car
klasse wordt gedeclareerd en de beschrijving die wordt weergegeven een 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
maakt een lijst met objecten met het type Car
. De waarden van de objecten worden geïnstantieerd vanuit de Car
, ConvertibleCar
en Minivan
klassen. DescribeCar
wordt aangeroepen op elk element van de lijst. De volgende code toont de definitie van 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("----------");
}
}
De volgende uitvoer wordt weergegeven. U ziet dat dit hetzelfde is als de uitvoer die wordt weergegeven door TestCars1
. De ShowDetails
methode van de ConvertibleCar
klasse wordt niet aangeroepen, ongeacht of het type van het object , ConvertibleCar
zoals in TestCars1
, of Car
, zoals in TestCars2
. Daarentegen car3
wordt de ShowDetails
methode in beide gevallen aangeroepen vanuit de Minivan
klasse, ongeacht of deze type Minivan
of type Car
heeft.
// TestCars2
// ----------
// Four wheels and an engine.
// Standard transportation.
// ----------
// Four wheels and an engine.
// Standard transportation.
// ----------
// Four wheels and an engine.
// Carries seven people.
// ----------
Methoden TestCars3
en TestCars4
voltooi het voorbeeld. Deze methoden roepen ShowDetails
rechtstreeks aan, eerst van objecten die zijn gedeclareerd om type ConvertibleCar
en () te hebben en Minivan
vervolgensTestCars3
van objecten die zijn gedeclareerd om het type Car
(TestCars4
) te hebben. De volgende code definieert deze twee methoden.
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();
}
De methoden produceren de volgende uitvoer, die overeenkomt met de resultaten uit het eerste voorbeeld in dit onderwerp.
// TestCars3
// ----------
// A roof that opens up.
// Carries seven people.
// TestCars4
// ----------
// Standard transportation.
// Carries seven people.
De volgende code toont het volledige project en de uitvoer ervan.
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.");
}
}
}