Arv och polymorfism
↑Exemplen är oberoende C#-utdrag för moderna .NET-konsolprojekt, om inget annat anges. Klassdeklarationer och toppnivåkod kan placeras i samma Program.cs-fil, med toppnivåkoden först.
Snabböversikt
Section titled “Snabböversikt”Arv uttrycker en är-en-relation. Polymorfism låter anropare använda en bastyp medan det faktiska objektet avgör vilken överskuggad metod som körs.
Så fungerar det
Section titled “Så fungerar det”Basklasser och härledda klasser
Section titled “Basklasser och härledda klasser”En C#-klass kan ärva från en enda basklass. Den härledda klassen får tillgång till basklassens åtkomliga medlemmar. Använd arv när typer verkligen är utbytbara, inte bara för att dela några kodrader.
public class Character{ public string Name { get; init; } = "Unknown"; public virtual string Describe() => Name;}public class Mage : Character{ public override string Describe() => $"Mage: {base.Describe()}";}Virtuella anrop och override
Section titled “Virtuella anrop och override”Markera en metod i basklassen med virtual (eller abstract) och skriv över den i härledda klasser. Ett anrop genom en basreferens använder objektets verkliga implementation. new som döljer en medlem är inte samma sak som override.
Det här kodutdraget fortsätter exemplet med Character och Mage ovan.
Character hero = new Mage { Name = "Ari" };Console.WriteLine(hero.Describe()); // Mage: AriNär komposition är bättre
Section titled “När komposition är bättre”Arv kopplar klasser till en gemensam hierarki. För utbytbara beteenden kan komposition vara bättre: en klass innehåller ett separat objekt bakom ett interface. Det blir ofta enklare att testa och förändra.
public interface IMovement { void Move(); }public class PlayerController{ private readonly IMovement movement; public PlayerController(IMovement movement) => this.movement = movement; public void Tick() => movement.Move();}Fördjupning: det verkliga objektet avgör beteendet
Section titled “Fördjupning: det verkliga objektet avgör beteendet”Varför fungerar override?
Section titled “Varför fungerar override?”En variabel kan deklareras som en basklasstyp men peka på ett objekt av en härledd klass. Om metoden är virtual i basklassen och override i underklassen väljer körmiljön den mest specifika implementationen för objektet. Variabelns deklarerade typ avgör vilka medlemmar som går att anropa; objektets verkliga typ avgör vilken överskuggad implementation som körs.
Enemy enemy = new FlyingEnemy();Console.WriteLine(enemy.Move()); // "Flying"
public class Enemy{ public virtual string Move() => "Walking";}public sealed class FlyingEnemy : Enemy{ public override string Move() => "Flying";}Utan virtual/override innebär en metod med new att en ärvd medlem döljs, inte att den ersätts polymorfiskt. Vilken metod som anropas kan då bero på uttryckets typ vid kompilering. Använd override när detta är avsikten och base.Move() när underklassen ska utöka basklassens beteende.
Is-a jämfört med has-a
Section titled “Is-a jämfört med has-a”Arv passar när den härledda klassen faktiskt är en specialisering av basklassen och uppfyller dess kontrakt. Komposition innebär att objektet har en medarbetare, till exempel en Player med HealthComponent eller MovementStrategy. Föredra komposition när beteenden varierar oberoende av varandra eller behöver bytas under körning. Djupa arvshierarkier tenderar att koppla ihop många ansvar.
Unity har en extra begränsning
Section titled “Unity har en extra begränsning”Dina spelskript ärver redan från MonoBehaviour, och C# tillåter bara en klass som direkt basklass. Interface som IDamageable låter flera olika komponenttyper erbjuda en gemensam förmåga utan att de behöver samma extra basklass. Räkna inte med att en vanlig metod körs automatiskt på en härledd MonoBehaviour; Unity anropar bara relevanta livscykelmeddelanden och sådant som du uttryckligen anropar.
När och varför?
Section titled “När och varför?”Använd virtual när en kontrollerad utbyggnad behövs. Välj komposition för delade förmågor som inte betyder att typerna är samma slags objekt.
Vanligt misstag
Section titled “Vanligt misstag”Överskuggning kräver rätt signatur och en överridbar metod i basklassen. C# stöder inte multipelt klassarv.
Testa själv
Section titled “Testa själv”Skapa Animal och skriv över Speak i Dog. Anropa genom en Animal-referens.
Visa ett lösningsförslag
Deklarera public virtual string Speak() och public override string Speak().
