Obtener acceso a los miembros de clase base desde una clase derivada

Completado

Una clase derivada que reemplaza o invalida un método o propiedad de clase base todavía puede tener acceso al método o la propiedad en la clase base mediante la palabra clave base. Esto permite llamar a constructores, métodos y propiedades de clase base de miembros invalidados de una clase derivada. Mediante el uso de la palabra clave base, puede asegurarse de que la clase derivada reutiliza y amplía de forma correcta la funcionalidad proporcionada por la clase base.

La palabra clave base se usa para realizar las siguientes tareas:

  • Para llamar a un método de clase base desde un método invalidado de la clase derivada.
  • Para implementar un constructor de clase base desde dentro del constructor de la clase derivada.

La palabra clave base tiene las restricciones siguientes:

  • La palabra clave base solo se puede usar en un constructor, un método de instancia o un descriptor de acceso de propiedad de instancia.
  • La palabra clave base no se puede usar en un método estático. Si intenta usar la palabra clave base en un método estático, se generará un error.

Al implementar la palabra clave base en una clase derivada, el código usa la clase base especificada en la declaración de clase. Por ejemplo, si especifica la clase ClassC : ClassB en la declaración de clase, la palabra clave base permite que el código acceda a los miembros de ClassB desde ClassC. No importa si la clase ClassB hereda de la clase ClassA.

Acceso a propiedades y métodos de clase base desde una clase derivada

El acceso a las propiedades y métodos de una clase base desde una clase derivada es un requisito común al implementar la herencia. En el código siguiente se muestra la sintaxis para implementar la palabra clave base:

base.MemberName

Observe que la palabra clave base y el nombre del miembro de clase base están separados por un punto (.). MemberName puede ser una propiedad, un método o un campo de la clase base.

En el código siguiente se muestra cómo obtener acceso a las propiedades y métodos de clase base desde una clase derivada:


// create an instance of the derived classes
DerivedClass1 derivedClass1 = new DerivedClass1();

// demonstrate the overridden methods of the derived class
Console.WriteLine("Calling the methods of DerivedClass1...\n");
Console.WriteLine($"Method1 in the derived class overrides the base class and provides a custom message: {derivedClass1.Method1()}");

derivedClass1.Method2();

/*Output:
Calling the methods of DerivedClass1...

Method1 in the base class is abstract and can't be called.
Method1 in the derived class overrides the base class and provides a custom message: Message from the overridden Method1 in DerivedClass1

Method2 in the derived class calls base.Method2 (reuses the base class implementation)
Method2 in the base class implements common behavior and returns true/false
Method2 in the derived class accesses base class Property2: Base - Property2

Method2 in the derived class uses base class members to modify and extend functionality
*/

public abstract class BaseClass
{
    public abstract string Property1 { get; set; }
    public virtual string Property2 { get; set; } = "Base - Property2";

    public abstract string Method1();

    public virtual bool Method2()
    {
        Console.WriteLine("Method2 in the base class implements common behavior and returns true/false");
        return true;
    }
}

public class DerivedClass1 : BaseClass
{
    public override string Property1 { get; set; } = "Derived - Property1";
    public new string Property2 { get; set; } = "Derived - Property2";

    public override string Method1()
    {
        // Method1 of the base class is abstract and can't be called
        Console.WriteLine($"Method1 in the base class is abstract and can't be called.");
        
        // Return the base.Method1 response additional information specific to DerivedClass1
        return $"Message from the overridden Method1 in DerivedClass1";
    }

    public override bool Method2()
    {
        // Call base class method to implement common behavior
        Console.WriteLine($"\nMethod2 in the derived class calls base.Method2 (reuses the base class implementation)");
        bool baseMethod2Success = base.Method2();

        // Access base class Property2
        string baseProperty2Value = base.Property2;
        Console.WriteLine($"Method2 in the derived class accesses base class Property2: {baseProperty2Value}");

        // implement derived class logic that involves base class information
        if (baseMethod2Success && baseProperty2Value == "Base - Property2")
        {
            Console.WriteLine("\nMethod2 in the derived class uses base class members to modify and extend functionality");
            return true;
        }
        else
        {
            Console.WriteLine("Method2 in the derived class can implement alternate behavior");
        }

        return false;
    }
}

En este ejemplo de código, la clase DerivedClass1 hereda de BaseClass e invalida sus métodos para ampliar su funcionalidad. El código implementa los pasos siguientes:

  1. Se crea una instancia de DerivedClass1 mediante la instrucción DerivedClass1 derivedClass1 = new DerivedClass1();. Esta instancia de clase derivada se usa para llamar a y demostrar los métodos invalidados de la clase derivada.

  2. El código llama a la clase Method1 derivada desde dentro de una instrucción Console.WriteLine. El invalidado Method1 no puede tener acceso al resumen Method1 de la clase base. En su lugar, proporciona su propia implementación que devuelve una cadena que indica que es única para la clase derivada.

  3. El código llama a Method2 la clase derivada. La invalidada Method2 usa base.Method2 para reutilizar la implementación de la clase baseMethod2. El método accede al Property2 de la clase base e imprime su valor. A continuación, el método invalidado usa el valor booleano devuelto por el Method2 de la clase base y el valor de Property2, para ampliar la funcionalidad de Method2 o implementa un comportamiento alternativo En este paso se muestra cómo la clase derivada puede basar y modificar el comportamiento del método de clase base.

Nota

Se recomienda a los miembros virtuales usen base para llamar a la implementación de clase base de ese miembro en su propia implementación. Permitir que se produzca el comportamiento de la clase base permite que la clase derivada se centre en la implementación del comportamiento específico de la clase derivada. Si no se llama a la implementación de la clase base, es hasta la clase derivada para que su comportamiento sea compatible con el comportamiento de la clase base.

Acceso a constructores de clase base desde una clase derivada

Se puede acceder a los constructores de clase de la clase base desde constructores de la clase derivada mediante la palabra clave base.

En el código siguiente se muestra cómo acceder a constructores de clase base desde una clase derivada:


// create an instance of the derived classes
DerivedClass1 derivedClass1 = new DerivedClass1("Derived1 - Property1", "Derived1 - Property2");

// demonstrate the overridden methods of the derived class
Console.WriteLine("Calling the methods of DerivedClass1...\n");
Console.WriteLine($"Method1 in the derived class appends derived class information to the return value: {derivedClass1.Method1()}");

derivedClass1.Method2();

/*Output:
Calling the methods of DerivedClass1...

Method1 in the derived class calls base.Method1. base.Method1 returns: base.Method1 results
Method1 in the derived class appends derived class information to the return value: base.Method1 results - plus information specific to DerivedClass1

Method2 in the derived class calls base.Method2 (reuses the base class implementation)
Method2 in the base class implements common behavior and returns true/false
Method2 in the derived class accesses base class Property2: Base - Property2

Method2 in the derived class uses base class members to modify and extend functionality
*/

public abstract class BaseClass
{
    public abstract string Property1 { get; set; }
    public virtual string Property2 { get; set; }

    public BaseClass(string property1, string property2)
    {
        Property1 = property1;
        Property2 = property2;
    }

    public virtual string Method1()
    {
        return "base.Method1 results";
    }

    public virtual bool Method2()
    {
        Console.WriteLine("Method2 in the base class implements common behavior and returns true/false");
        return true;
    }
}

public class DerivedClass1 : BaseClass
{
    public override string Property1 { get; set; }
    public new string Property2 { get; set; }

    public DerivedClass1(string property1, string property2) : base(property1, "Base - Property2")
    {
        Property1 = property1;
        Property2 = property2;
    }

    public override string Method1()
    {
        // Method1 of the base class is now virtual
        Console.WriteLine($"Method1 in the derived class calls base.Method1. base.Method1 returns: {base.Method1()}");
        
        // Return the base.Method1 response additional information specific to DerivedClass1
        return $"{base.Method1()} - plus information specific to DerivedClass1";
    }

    public override bool Method2()
    {
        // Call base class method to implement common behavior
        Console.WriteLine($"\nMethod2 in the derived class calls base.Method2 (reuses the base class implementation)");
        bool baseMethod1Success = base.Method2();

        // Access base class Property2
        string baseProperty2Value = base.Property2;
        Console.WriteLine($"Method2 in the derived class accesses base class Property2: {baseProperty2Value}");

        // implement derived class logic that involves base class information
        if (baseMethod1Success && baseProperty2Value == "Base - Property2")
        {
            Console.WriteLine("\nMethod2 in the derived class uses base class members to modify and extend functionality");
            return true;
        }
        else
        {
            Console.WriteLine("Method2 in the derived class can implement alternate behavior");
        }

        return false;
    }
}

Es importante llamar al constructor de clase base desde el constructor de clase derivada. Por ejemplo, cuando el constructor de clase base inicializa las propiedades comunes que usa la clase derivada. Al llamar al constructor de clase base desde el constructor de clase derivada, asegúrese de que las propiedades comunes se inicializan antes de que se ejecute el constructor de clase derivada.

Tenga en cuenta el código siguiente:


public abstract class Vehicle
{
    public virtual int Speed { get; set; }
    public virtual int Fuel { get; set; }

    public Vehicle(int speed, int fuel)
    {
        Speed = speed;
        Fuel = fuel;
    }

    public virtual void Drive()
    {
        Console.WriteLine("Vehicle is driving");
    }
}

public class Car : Vehicle
{
    public int NumberOfDoors { get; set; }
    public int TrunkCapacity { get; set; }

    public Car(int speed, int fuel, int numberOfDoors) : base(speed, fuel)
    {
        NumberOfDoors = numberOfDoors;
        // Initialize TrunkCapacity based on the Speed and Fuel properties of the base class
        TrunkCapacity = CalculateTrunkCapacity(Speed, Fuel);
    }

    private int CalculateTrunkCapacity(int speed, int fuel)
    {
        // Example logic to calculate trunk capacity based on speed and fuel
        return (speed + fuel) / 2;
    }

    public override void Drive()
    {
        base.Drive();
        Console.WriteLine("Car is driving with additional features");
    }
}

class Program
{
    static void Main()
    {
        Car car = new Car(100, 50, 4);
        Console.WriteLine($"Speed: {car.Speed}, Fuel: {car.Fuel}, NumberOfDoors: {car.NumberOfDoors}, TrunkCapacity: {car.TrunkCapacity}");
        car.Drive();
    }
}

Observe que el constructor de clase Car llama al constructor de clase base mediante la palabra clave base. Llamar primero al constructor de clase base garantiza que las propiedades Speed y Fuel de la clase base de Vehicle se inicializan correctamente antes de que se ejecute el Car constructor de clase. Esta secuencia de eventos es importante porque la propiedad TrunkCapacity de la clase Car se inicializa mediante las propiedades Speed y Fuel de la clase base Vehicle.

Resumen

Tenga en cuenta las instrucciones siguientes al acceder a los miembros de clase base desde una clase derivada:

  • Use la palabra clave base para tener acceso a los miembros de clase base desde una clase derivada.
  • Use la palabra clave base para llamar a constructores de clase base de constructores de clase derivadas.
  • Use la palabra clave base para acceder a los campos, propiedades y métodos de clase base de métodos invalidados en una clase derivada.