Интерфейсы в C#. Виртуальные методы.
Интерфейс содержит определения для группы связанных функциональных возможностей, которые может реализовать класс или структура. С помощью интерфейсов можно, например, включить в класс поведение из нескольких источников. Эта возможность очень важна в C#, поскольку этот язык не поддерживает множественное наследование классов. Кроме того, необходимо использовать интерфейс, если требуется имитировать наследование для структур, поскольку они не могут фактически наследовать от другой структуры или класса. Интерфейс определяется с помощью ключевого слова interface, как показано в следующем примере.
interface IEquatable<T>
{
bool Equals(T obj);
}
Любой объект (класс или структура), реализующий интерфейс IEquatable
,
должен содержать определение для метода IEquatable.Equals
, соответствующее сигнатуре,
которую задает интерфейс. В результате вы можете быть уверены, что класс, реализующий IEquatable<T>
,
содержит метод Equals
, с помощью которого экземпляр этого класса может определить, равен ли он другому
экземпляру того же класса.
Ниже приведен класс Car
, реализующий интерфейс IEquatable
public class Car : IEquatable<Car>
{
public string Make {get; set;}
public string Model { get; set; }
public string Year { get; set; }
// Реализация интерфейса IEquatable<T>
public bool Equals(Car car)
{
if (this.Make == car.Make &&
this.Model == car.Model &&
this.Year == car.Year)
{
return true;
}
else
return false;
}
}
Сводные сведения по интерфейсам
Интерфейс имеет следующие свойства.
- Интерфейс подобен абстрактному базовому классу. Любой класс (или структура), реализующий интерфейс, должен реализовывать все его члены.
- Невозможно создать экземпляр интерфейса напрямую. Его члены реализуются любым классом (или структурой), реализующим интерфейс.
- Интерфейсы могут содержать события, индексаторы, методы и свойства.
- Интерфейсы не содержат реализацию методов.
- Класс или структура может реализовывать несколько интерфейсов. Класс может наследовать базовому классу и также реализовывать один или несколько интерфейсов.
Виртуальные методы
Ключевое слово virtual используется для изменения объявлений методов, свойств,
индексаторов и событий и разрешения их переопределения в производном классе.
Основным отличием от абстрактного метода, определяемым словом abstract
, является то, что наследник класса обязан
переопределять абстрактный метод, но не обязан переопределять виртуальный.
Например, этот метод может быть переопределен любым наследующим его классом:
public virtual double Area()
{
return x * y;
}
В этом примере класс Shape
содержит две координаты x, y и виртуальный метод Area()
.
Различные классы фигур, такие как Circle
, Cylinder
и Sphere
, наследуют класс Shape
, и для
каждой фигуры вычисляется площадь поверхности. Каждый производный класс обладает собственной
реализацией переопределения метода Area()
.
Обратите внимание, что наследуемые классы Circle
, Sphere
и Cylinder
используют конструкторы,
которые инициализируют базовый класс, как показано в следующем объявлении.
public Cylinder(double r, double h): base(r, h) {}
class TestClass
{
public class Shape
{
public const double PI = Math.PI;
protected double x, y;
public Shape()
{
}
public Shape(double x, double y)
{
this.x = x;
this.y = y;
}
public virtual double Area()
{
return x * y;
}
}
public class Circle : Shape
{
public Circle(double r) : base(r, 0)
{
}
public override double Area()
{
return PI * x * x;
}
}
class Sphere : Shape
{
public Sphere(double r) : base(r, 0)
{
}
public override double Area()
{
return 4 * PI * x * x;
}
}
class Cylinder : Shape
{
public Cylinder(double r, double h) : base(r, h)
{
}
public override double Area()
{
return 2 * PI * x * x + 2 * PI * x * y;
}
}
static void Main()
{
double r = 3.0, h = 5.0;
Shape c = new Circle(r);
Shape s = new Sphere(r);
Shape l = new Cylinder(r, h);
// Display results:
Console.WriteLine("Area of Circle = {0:F2}", c.Area());
Console.WriteLine("Area of Sphere = {0:F2}", s.Area());
Console.WriteLine("Area of Cylinder = {0:F2}", l.Area());
}
}