Condividi tramite


abstract (Riferimenti per C#)

Il abstract modificatore indica che la destinazione ha un'implementazione mancante o incompleta. Usare il modificatore astratto con classi, metodi, proprietà, indicizzatori ed eventi. Usare il modificatore abstract in una dichiarazione di classe per indicare che una classe verrà usata solo come classe di base per altre classi e che non verrà creata un'istanza relativamente alla stessa. Le classi non astratte che derivano dalla classe astratta devono implementare membri contrassegnati come astratti.

Il riferimento al linguaggio C# documenta la versione rilasciata più di recente del linguaggio C#. Contiene anche la documentazione iniziale per le funzionalità nelle versioni di anteprima pubblica per la prossima versione del linguaggio di programmazione.

La documentazione identifica tutte le funzionalità introdotte nelle ultime tre versioni della lingua o nelle anteprime pubbliche correnti.

Suggerimento

Per trovare quando una funzionalità è stata introdotta per la prima volta in C#, vedere l'articolo sulla cronologia delle versioni del linguaggio C#.

Le classi astratte possono contenere entrambi i membri astratti (che non hanno implementazione e devono essere sottoposti a override nelle classi derivate) e membri completamente implementati (ad esempio metodi regolari, proprietà e costruttori). Questa funzionalità consente alle classi astratte di fornire funzionalità comuni, pur richiedendo classi derivate per implementare membri astratti specifici.

Annotazioni

I membri dell'interfaccia sono abstract per impostazione predefinita.

Classe astratta con membri misti

Nell'esempio seguente viene illustrata una classe astratta che contiene sia metodi implementati che membri astratti:

namespace LanguageKeywords;

public abstract class Vehicle
{
    protected string _brand;
    
    // Constructor - implemented method in abstract class
    public Vehicle(string brand) => _brand = brand;
    
    // Implemented method - provides functionality that all vehicles share
    public string GetInfo() => $"This is a {_brand} vehicle.";
    
    // Another implemented method
    public virtual void StartEngine() => Console.WriteLine($"{_brand} engine is starting...");
    
    // Abstract method - must be implemented by derived classes
    public abstract void Move();
    
    // Abstract property - must be implemented by derived classes  
    public abstract int MaxSpeed { get; }
}

public class Car : Vehicle
{
    public Car(string brand) : base(brand) { }
    
    // Implementation of abstract method
    public override void Move() => Console.WriteLine($"{_brand} car is driving on the road.");
    
    // Implementation of abstract property
    public override int MaxSpeed => 200;
}

public class Boat : Vehicle
{
    public Boat(string brand) : base(brand) { }
    
    // Implementation of abstract method
    public override void Move() => Console.WriteLine($"{_brand} boat is sailing on the water.");
    
    // Implementation of abstract property
    public override int MaxSpeed => 50;
}

public class AbstractExample
{
    public static void Examples()
    {
        // Cannot instantiate abstract class: Vehicle v = new Vehicle("Generic"); // Error!
        
        Car car = new Car("Toyota");
        Boat boat = new Boat("Yamaha");
        
        // Using implemented methods from abstract class
        Console.WriteLine(car.GetInfo());
        car.StartEngine();
        
        // Using abstract methods implemented in derived class
        car.Move();
        Console.WriteLine($"Max speed: {car.MaxSpeed} km/h");
        
        Console.WriteLine();
        
        Console.WriteLine(boat.GetInfo());
        boat.StartEngine();
        boat.Move();
        Console.WriteLine($"Max speed: {boat.MaxSpeed} km/h");
    }
}

class Program
{
    static void Main()
    {
        AbstractExample.Examples();
    }
}
/* Output:
This is a Toyota vehicle.
Toyota engine is starting...
Toyota car is driving on the road.
Max speed: 200 km/h

This is a Yamaha vehicle.
Yamaha engine is starting...
Yamaha boat is sailing on the water.
Max speed: 50 km/h
*/

In questo esempio la Vehicle classe astratta fornisce:

  • Membri implementati: GetInfo() metodo, StartEngine() metodo e costruttore: questi membri forniscono funzionalità comuni per tutti i veicoli.
  • Membri astratti: Move() metodo e MaxSpeed proprietà: questi membri devono essere implementati da ogni tipo di veicolo specifico.

Questa progettazione consente alla classe astratta di fornire funzionalità condivise garantendo al tempo stesso che le classi derivate implementino un comportamento specifico del veicolo.

Classe concreta derivata da una classe astratta

In questo esempio, la classe Square deve eseguire un'implementazione di GetArea poiché deriva da Shape:

abstract class Shape
{
    public abstract int GetArea();
}

class Square : Shape
{
    private int _side;

    public Square(int n) => _side = n;

    // GetArea method is required to avoid a compile-time error.
    public override int GetArea() => _side * _side;

    static void Main()
    {
        var sq = new Square(12);
        Console.WriteLine($"Area of the square = {sq.GetArea()}");
    }
}
// Output: Area of the square = 144

Le classi astratte hanno le caratteristiche seguenti:

  • Non è possibile creare un'istanza di una classe astratta.
  • Una classe astratta può contenere metodi astratti e funzioni di accesso.
  • Una classe astratta può anche contenere metodi, proprietà, campi e altri membri implementati che forniscono funzionalità alle classi derivate.
  • Non è possibile usare il sealed modificatore in una classe astratta perché i due modificatori hanno significati opposti. Il modificatore sealed impedisce a una classe che venga ereditata e il modificatore abstract richiede una classe da ereditare.
  • Una classe non astratta derivata da una classe astratta deve includere implementazioni effettive di tutte le funzioni di accesso e di tutti i metodi astratti ereditati.

Usare il abstract modificatore in una dichiarazione di metodo o proprietà per indicare che il metodo o la proprietà non contiene l'implementazione.

I metodi astratti hanno le caratteristiche seguenti:

  • Un metodo astratto è implicitamente un metodo virtuale.

  • Le dichiarazioni di metodi astratti sono consentite solo in classi astratte.

  • Poiché una dichiarazione di metodo astratto non fornisce alcuna implementazione effettiva, non esiste alcun corpo del metodo. La dichiarazione del metodo termina semplicemente con un punto e virgola. Ad esempio:

    public abstract void MyMethod();
    

    L'implementazione viene fornita da un metodo override, che è un membro di una classe non astratta.

  • È un errore usare i static modificatori o virtual in una dichiarazione di metodo astratto in un class tipo. È possibile dichiarare static abstract metodi e static virtual nelle interfacce.

    Le proprietà astratte si comportano come i metodi astratti, ad eccezione delle differenze nella sintassi di dichiarazione e di chiamata.

  • Si tratta di un errore per usare il abstract modificatore in una proprietà statica in un class tipo. È possibile dichiarare static abstract o static virtual proprietà nelle dichiarazioni di interfaccia.

  • È possibile eseguire l'override di una proprietà ereditata astratta in una classe derivata includendo una dichiarazione di proprietà che usa il override modificatore.

Per altre informazioni sulle classi astratte, vedere Classi e membri delle classi astratte e sealed.

Una classe astratta deve specificare l'implementazione per tutti i membri di interfaccia. Una classe astratta che implementa un'interfaccia può eseguire il mapping dei metodi di interfaccia su metodi astratti. Ad esempio:

interface I
{
    void M();
}

abstract class C : I
{
    public abstract void M();
}

Nell'esempio seguente la classe DerivedClass deriva da una classe BaseClassastratta . La classe astratta contiene un metodo astratto, AbstractMethod, e due proprietà astratte, X e Y.

// Abstract class
abstract class BaseClass
{
    protected int _x = 100;
    protected int _y = 150;

    // Abstract method
    public abstract void AbstractMethod();

    // Abstract properties
    public abstract int X { get; }
    public abstract int Y { get; }
}

class DerivedClass : BaseClass
{
    public override void AbstractMethod()
    {
        _x++;
        _y++;
    }

    public override int X   // overriding property
    {
        get
        {
            return _x + 10;
        }
    }

    public override int Y   // overriding property
    {
        get
        {
            return _y + 10;
        }
    }

    static void Main()
    {
        var o = new DerivedClass();
        o.AbstractMethod();
        Console.WriteLine($"x = {o.X}, y = {o.Y}");
    }
}
// Output: x = 111, y = 161

Nell'esempio precedente, se si prova a creare un'istanza della classe astratta tramite un'istruzione simile alla seguente:

BaseClass bc = new BaseClass();   // Error

Viene visualizzato un errore che indica che il compilatore non può creare un'istanza della classe astratta 'BaseClass'. Tuttavia, è possibile usare un costruttore di classe astratta, come illustrato nell'esempio seguente.

public abstract class Shape
{
    public string Color { get; set; }

    // Constructor of the abstract class
    protected Shape(string color)
    {
        Color = color;
        Console.WriteLine($"Created a shape with color {color}.");
    }

    // Abstract method that must be implemented by derived classes
    public abstract double CalculateArea();
}

public class Square : Shape
{
    public double Side { get; set; }

    // Constructor of the derived class calling the base class constructor
    public Square(string color, double side) : base(color)
    {
        Side = side;
    }

    public override double CalculateArea()
    {
        return Side * Side;
    }
}

public class Program
{
    public static void Main(string[] args)
     {
            Square square = new Square("red", 5);
            Console.WriteLine($"Area of the square: {square.CalculateArea()}");            
     }
}

La Shape classe è dichiarata abstract, il che significa che non è possibile crearne direttamente un'istanza. Funge invece da progetto per altre classi.

  • Anche se non è possibile creare oggetti di una classe astratta, può comunque avere un costruttore. Questo costruttore è in protectedgenere , ovvero solo le classi derivate possono accedervi. In questo caso, il costruttore Shape accetta un parametro color e inizializza la proprietà Color. Stampa anche un messaggio nella console. La parte public Square(string color, double side) : base(color) chiama il costruttore della classe base (Shape) e passa l'argomento color a quest'ultimo.
  • Shape Nella classe il costruttore definito accetta un colore come parametro protected Shape(string color). Ciò significa che C# non fornisce più automaticamente un costruttore senza parametri predefinito. Le classi derivate devono usare l'espressione : base(color) per richiamare il costruttore di base. L'impostazione del valore predefinito su color protected Shape(string color="green") consente di omettere l'espressione : base(color) nelle classi derivate. Il costruttore protected Shape(string color="green") imposta il colore su verde.

Specifiche del linguaggio C#

Per altre informazioni, vedere la specifica del linguaggio C#. La specifica del linguaggio costituisce il riferimento ufficiale principale per la sintassi e l'uso di C#.

Vedi anche