Comparteix via


abstract (Referencia de C#)

El abstract modificador indica que su destino tiene una implementación incompleta o que falta. Use el modificador abstracto con clases, métodos, propiedades, indexadores y eventos. Use el modificador abstract en una declaración de clase para indicar que una clase está diseñada como clase base de otras clases, no para crear instancias por sí misma. Las clases no abstractas que derivan de la clase abstracta deben implementar miembros marcados como abstractos.

La documentación de referencia del lenguaje C# cubre la versión más reciente publicada del lenguaje C#. También contiene documentación inicial sobre las características de las versiones preliminares públicas de la próxima versión del lenguaje.

La documentación identifica cualquier característica introducida por primera vez en las últimas tres versiones del idioma o en las versiones preliminares públicas actuales.

Sugerencia

Para buscar cuándo se introdujo por primera vez una característica en C#, consulte el artículo sobre el historial de versiones del lenguaje C#.

Las clases abstractas pueden contener miembros abstractos (que no tienen ninguna implementación y deben invalidarse en clases derivadas) y miembros totalmente implementados (como métodos normales, propiedades y constructores). Esta característica permite que las clases abstractas proporcionen funcionalidad común, a la vez que requieren clases derivadas para implementar miembros abstractos específicos.

Nota:

Los miembros de la interfaz son abstract de forma predeterminada.

Clase abstracta con miembros mixtos

En el ejemplo siguiente se muestra una clase abstracta que contiene los métodos implementados y los miembros abstractos:

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
*/

En este ejemplo, la Vehicle clase abstracta proporciona:

  • Miembros implementados: GetInfo() método, StartEngine() método y constructor: estos miembros proporcionan una funcionalidad común para todos los vehículos.
  • Miembros abstractos: Move() método y MaxSpeed propiedad: cada tipo de vehículo específico debe implementar estos miembros.

Este diseño permite que la clase abstracta proporcione funcionalidad compartida al tiempo que garantiza que las clases derivadas implementen un comportamiento específico del vehículo.

Clase concreta derivada de una clase abstracta

En este ejemplo, la clase Square debe proporcionar una implementación de GetArea porque se deriva de 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

Las clases abstractas tienen las siguientes características:

  • No se puede crear una instancia de una clase abstracta.
  • Una clase abstracta puede contener métodos abstractos y descriptores de acceso.
  • Una clase abstracta también puede contener métodos, propiedades, campos y otros miembros implementados que proporcionan funcionalidad a las clases derivadas.
  • No se puede usar el sealed modificador en una clase abstracta porque los dos modificadores tienen significados opuestos. El modificador sealed impide que una clase se herede y el modificador abstract requiere que una clase se herede.
  • Una clase no abstracta que derive de una clase abstracta debe incluir implementaciones reales de todos los descriptores de acceso y métodos abstractos heredados.

Use el abstract modificador en una declaración de método o propiedad para indicar que el método o la propiedad no contiene la implementación.

Los métodos abstractos tienen las siguientes características:

  • Un método abstracto es, implícitamente, un método virtual.

  • Solo se permiten declaraciones de métodos abstractos en clases abstractas.

  • Dado que una declaración de método abstracto no proporciona ninguna implementación real, no hay ningún cuerpo del método. La declaración del método simplemente termina con un punto y coma. Por ejemplo:

    public abstract void MyMethod();
    

    La implementación la proporciona un método override, que es un miembro de una clase no abstracta.

  • Es un error usar los static modificadores o virtual en una declaración de método abstracto en un class tipo. Puede declarar static abstract métodos y static virtual en interfaces.

    Las propiedades abstractas se comportan como métodos abstractos, salvo por las diferencias en la sintaxis de declaración e invocación.

  • Es un error usar el abstract modificador en una propiedad estática de un class tipo. Puede declarar static abstract propiedades o static virtual en declaraciones de interfaz.

  • Una propiedad heredada abstracta se puede invalidar en una clase derivada mediante la inclusión de una declaración de propiedad que usa el override modificador .

Para obtener más información sobre las clases abstractas, vea Clases y miembros de clase abstractos y sellados (Guía de programación de C#).

Una clase abstracta debe proporcionar implementación para todos los miembros de interfaz. Una clase abstracta que implemente una interfaz podría asignar los métodos de interfaz a métodos abstractos. Por ejemplo:

interface I
{
    void M();
}

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

En el ejemplo siguiente, la clase DerivedClass deriva de una clase BaseClassabstracta . La clase abstracta contiene un método abstracto, AbstractMethod, y dos propiedades abstractas, X y 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

En el ejemplo anterior, si intenta crear una instancia de la clase abstracta mediante una instrucción como esta:

BaseClass bc = new BaseClass();   // Error

Aparece un error que indica que el compilador no puede crear una instancia de la clase abstracta "BaseClass". No obstante, puede usar un constructor de clase abstracta, como se muestra en el ejemplo siguiente.

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 clase se declara abstract, lo que significa que no se puede crear una instancia directamente. En su lugar, sirve como plano técnico para otras clases.

  • Aunque no se pueden crear objetos de una clase abstracta, todavía puede tener un constructor. Este constructor suele ser protected, lo que significa que solo las clases derivadas pueden acceder a él. En este caso, el constructor Shape toma un parámetro color e inicializa la propiedad Color. También imprime un mensaje en la consola. La parte public Square(string color, double side) : base(color) llama al constructor de la clase base (Shape) y pasa el argumento color a él.
  • En la Shape clase , el constructor definido toma un color como parámetro protected Shape(string color). Esto significa que C# ya no proporciona automáticamente un constructor sin parámetros predeterminado. Las clases derivadas deben usar la : base(color) expresión para invocar el constructor base. Establecer el valor predeterminado en color protected Shape(string color="green") permite omitir la : base(color) expresión en clases derivadas. El constructor protected Shape(string color="green") establece el color en verde.

Especificación del lenguaje C#

Para obtener más información, consulte la Especificación del lenguaje C#. La especificación del lenguaje es la fuente definitiva de la sintaxis y el uso de C#.

Consulte también