Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Модификатор abstract указывает, что изменяемый элемент имеет отсутствующую или неполную реализацию. Модификатор abstract можно использовать с классами, методами, свойствами, индексаторами и событиями. Используйте модификатор abstract в объявлении класса, чтобы указать, что класс предназначен только для использования в качестве базового класса для других классов и не должен быть создан сам по себе. Элементы с пометкой abstract должны быть реализованы не абстрактными классами, производными от абстрактного класса.
Абстрактные классы могут содержать абстрактные члены (которые не имеют реализации и должны быть переопределены в производных классах) и полностью реализованные члены (например, обычные методы, свойства и конструкторы). Это позволяет абстрактным классам предоставлять общие функциональные возможности, пока не требуется производные классы для реализации конкретных абстрактных элементов.
Пример 1. Абстрактный класс с смешанными элементами
В следующем примере демонстрируется абстрактный класс, содержащий как реализованные методы, так и абстрактные члены:
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
*/
В этом примере абстрактный Vehicle класс предоставляет:
-
Реализованные элементы:
GetInfo()метод,StartEngine()метод и конструктор — они предоставляют общие функциональные возможности для всех транспортных средств. -
Абстрактные члены:
Move()метод иMaxSpeedсвойство — они должны быть реализованы по каждому конкретному типу транспортного средства.
Эта конструкция позволяет абстрактным классам предоставлять общие функциональные возможности, гарантируя, что производные классы реализуют поведение, зависящее от транспортного средства.
Пример 2
В этом примере класс Square должен обеспечивать реализацию GetArea, поскольку является производным от класса 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
Абстрактные классы предоставляют следующие возможности:
Создавать экземпляры абстрактного класса нельзя.
Абстрактный класс может содержать абстрактные методы и методы доступа.
Абстрактный класс также может содержать реализованные методы, свойства, поля и другие члены, предоставляющие функциональные возможности производным классам.
Изменить абстрактный класс с модификатором sealed нельзя, так как два этих модификатора имеют взаимоисключающие значения. Модификатор
sealedзапрещает наследование класса, в то время как модификаторabstractуказывает, что класс обязан иметь производные классы.Неабстрактный класс, производный от абстрактного класса, должен включать фактические реализации всех наследуемых абстрактных методов и методов доступа.
Модификатор abstract в объявлении метода или свойства позволяет указать, что этот метод или свойство не содержат реализации.
Абстрактные методы предоставляют следующие возможности:
Абстрактный метод неявно представляет собой виртуальный метод.
Объявления абстрактных методов допускаются только в абстрактных классах.
Поскольку объявление абстрактного метода не предоставляет фактической реализации, тело метода отсутствует, а объявление метода заканчивается точкой с запятой, и фигурных скобок ({ }) после подписи нет. Например:
public abstract void MyMethod();Реализация предоставляется методом override, который является членом неабстрактного класса.
В объявлении абстрактного метода нельзя использовать статические или виртуальные модификаторы.
Действие абстрактных свойств аналогично абстрактным методам, за исключением отличий в синтаксисе объявлений и вызовов.
Использование модификатора
abstractв статическом свойстве является недопустимым.Абстрактное наследуемое свойство можно переопределить в производном классе, включив объявление свойства, которое использует модификатор override.
Дополнительные сведения об абстрактных классах см. в статье Abstract and Sealed Classes and Class Members (Абстрактные и запечатанные классы и члены классов).
Абстрактный класс должен предоставлять реализацию для всех членов интерфейса.
Абстрактный класс, реализующий интерфейс, может сопоставлять методы интерфейса с абстрактными методами. Например:
interface I
{
void M();
}
abstract class C : I
{
public abstract void M();
}
Пример 3
В следующем примере класс DerivedClass является производным от абстрактного класса BaseClass. Абстрактный класс содержит абстрактный метод, AbstractMethod, и два абстрактных свойства, X и 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
В предыдущем примере при попытке создать экземпляр абстрактного класса с помощью оператора вида:
BaseClass bc = new BaseClass(); // Error
Выдается сообщение об ошибке, указывающее, что компилятор не может создать экземпляр абстрактного класса BaseClass.
Тем не менее можно использовать конструктор абстрактного класса, как показано в примере ниже.
Пример 4
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()}");
}
}
Класс Shape объявляется abstract, что означает, что он не может быть создан напрямую. Вместо этого он служит схемой для других классов.
- Несмотря на то, что объекты абстрактного класса невозможно создать, он по-прежнему может иметь конструктор. Этот конструктор обычно
protected, то есть доступ к нему можно получить только из производных классов. В этом случае конструкторShapeпринимает параметрcolorи инициализирует свойствоColor. Он также выводит сообщение в консоль. Частьpublic Square(string color, double side) : base(color)вызывает конструктор базового класса (Shape) и передает в него аргументcolor. - В классе Shape определенный конструктор принимает цвет в качестве параметра
protected Shape(string color). Это означает, что C# больше не предоставляет конструктор без параметров по умолчанию, поэтому производные классы должны использовать выражение: base(color)для вызова базового конструктора. Установка значения по умолчанию для цветаprotected Shape(string color="green")позволит опустить выражение: base(color)в производных классах, при этом будет вызван конструкторprotected Shape(string color="green"), устанавливающий цвет зелёный.
Спецификация языка C#
Дополнительные сведения см. в спецификации языка C#. Спецификация языка является предписывающим источником информации о синтаксисе и использовании языка C#.