---
title: Классы и интерфейсы
seo:
  title: "Классы и интерфейсы — С# Developer"
  description: "Тема «Классы и интерфейсы» для собеседования С# Developer. Что такое класс? Чем отличается класс от абстрактного класса?"
---

[Все темы С# Developer](/s-developer)

## <strong>Что такое класс?</strong> [#q-14bee738d69b81479a72d469b1b18328]

<strong>Класс</strong> — это шаблон или описание для создания объектов, который
объединяет данные (поля) и методы (функции) для работы с этими данными.

:::note[Ссылки для изучения]

1. [Классы в C#](https://learn.microsoft.com/ru-ru/dotnet/csharp/fundamentals/types/classes)
   :::

---

## <strong>Чем отличается класс от абстрактного класса?</strong> [#q-14bee738d69b81538480d92ee320bc35]

Основное различие между классом и абстрактным классом в .NET&#58;

{/* prettier-ignore */}
- <strong>Классы</strong>&#58;

    - Предоставляют конкретную реализацию.

    - Могут быть непосредственно инициализированы.

- <strong>Абстрактные классы</strong>&#58;

    - Это абстрактные шаблоны.

    - Требуют реализации конкретными производными классами.

:::note[Ссылки для изучения]

1. [Разница между обычным классом и абстрактным в C#](https://tr-page.yandex.ru/translate?lang=en-ru&url=https%3A%2F%2Fstackoverflow.com%2Fquestions%2F2209890%2Fwhats-the-difference-between-an-abstract-class-and-a-class-with-only-protected)
   :::

---

## <strong>Чем отличается абстрактный класс от интерфейса? Для чего нужны интерфейсы и какие задачи они выполняют?</strong> [#q-14bee738d69b812e9632e675ca522498]

Абстрактный класс и интерфейс в C# используются для определения контрактов, которые классы должны реализовать, но они имеют несколько ключевых отличий и применяются в разных ситуациях.

#### Отличия между абстрактным классом и интерфейсом

{/* prettier-ignore */}
1. <strong>Наследование&#58;</strong>

    - Абстрактный класс&#58; Класс может наследоваться только от одного абстрактного класса.

    - Интерфейс&#58; Класс может реализовывать множество интерфейсов.

1. <strong>Реализация методов&#58;</strong>

    - Абстрактный класс&#58; Может содержать как абстрактные методы (без реализации), так и методы с реализацией.

    - Интерфейс&#58; Не содержит реализации методов (до C# 8.0). Начиная с C# 8.0, интерфейсы могут содержать реализации методов по умолчанию.

1. <strong>Полиморфизм&#58;</strong>

    - Абстрактный класс&#58; Поддерживает полиморфизм через виртуальные методы и абстрактные методы.

    - Интерфейс&#58; Поддерживает полиморфизм через методы интерфейса, которые должны быть реализованы в классе.

1. <strong>Модификаторы доступа&#58;</strong>

    - Абстрактный класс&#58; Может содержать поля, свойства и методы с различными модификаторами доступа (private, protected, public и т.д.).

    - Интерфейс не хранит поля экземпляра. Начиная с C# 8 интерфейсы могут содержать реализации по умолчанию, статические поля и члены с модификаторами доступа; точные возможности зависят от версии C# и runtime.

Интерфейсы нужны для определения набора методов и свойств, которые класс должен реализовать, обеспечивая определенный контракт без указания способа его реализации. Это полезно для&#58;

1. <strong>Поддержки полиморфизма&#58;</strong> Позволяет использовать разные
   классы через общий интерфейс, обеспечивая гибкость и расширяемость кода.

1. <strong>Многоразовости кода&#58;</strong> Класс может реализовывать несколько
   интерфейсов, что позволяет комбинировать функциональность из разных
   источников.

1. <strong>Снижения связности кода&#58;</strong> Позволяет писать более гибкий и
   тестируемый код. Интерфейсы способствуют инверсии управления (IoC) и
   внедрению зависимостей (DI).

1. <strong>Упрощения тестирования&#58;</strong> Интерфейсы облегчают создание
   мок-объектов для юнит-тестирования.

Пример использования интерфейса&#58;

```csharp
public interface IFlyable
{
    void Fly();
}

public class Bird : IFlyable
{
    public void Fly()
    {
        Console.WriteLine("Bird is flying.");
    }
}

public class Airplane : IFlyable
{
    public void Fly()
    {
        Console.WriteLine("Airplane is flying.");
    }
}

public class Program
{
    public static void Main(string[] args)
    {
        IFlyable[] flyingObjects = { new Bird(), new Airplane() };

        foreach (var obj in flyingObjects)
        {
            obj.Fly();
        }
    }
}
```

В этом примере интерфейс <code>IFlyable</code> определяет метод <code>Fly</code>, который реализуют оба класса <code>Bird</code> и <code>Airplane</code>. Программа может работать с объектами, реализующими интерфейс, независимо от их конкретных типов.

:::note[Ссылки для изучения]

1. [Интерфейсы или абстрактные классы в C#](https://metanit.com/sharp/patterns/1.3.php)
   :::

---

## <strong>Какие вы знаете модификаторы доступа?</strong> [#q-14bee738d69b81f7a856f8a06fe8c2df]

В C# есть пять основных модификаторов доступа, которые определяют уровень видимости и доступности классов и членов классов (полей, методов, свойств и т.д.)&#58;

1. <strong>public</strong> - Доступен для всех. Члены, объявленные как
   <code>public</code>, могут быть доступны из любого кода.

1. <strong>private</strong> - Доступен только внутри класса или структуры. Это
   самый ограничительный уровень доступа.

1. <strong>protected</strong> - Доступен внутри класса и его производных
   классов. Используется для обеспечения доступа к членам только в рамках
   наследования.

1. <strong>internal</strong> - Доступен в пределах одной сборки. Члены с
   модификатором <code>internal</code> могут быть использованы в любом коде,
   который находится в той же сборке, но недоступны из других сборок.

1. <strong>protected internal</strong> - Доступен в пределах одной сборки или
   производных классов. Это объединение модификаторов <code>protected</code> и
   <code>internal</code>, дающее доступ либо в пределах одной сборки, либо в
   производных классах, даже если они находятся в другой сборке.

Дополнительно в C# 7.2 был введен модификатор <strong>private protected</strong>&#58;

- <strong>private protected</strong> - Доступен внутри класса или структуры и
  его производных классов, которые находятся в той же сборке. Это комбинация
  модификаторов <code>private</code> и <code>protected</code>.

:::note[Ссылки для изучения]

1. [Модификаторы доступа в C#](https://metanit.com/sharp/tutorial/3.2.php)
   :::

---

## <strong>В чем разница между обычным классом и статическим?</strong> [#q-14bee738d69b8167904af27dbd87ce9e]

В C# есть несколько ключевых различий между обычным (нестатическим) классом и статическим классом&#58;

{/* prettier-ignore */}
1. <strong>Экземпляры&#58;</strong>

    - <strong>Обычный класс&#58;</strong> Может создавать экземпляры (объекты) с использованием оператора <code>new</code>.

    - <strong>Статический класс&#58;</strong> Нельзя создавать экземпляры. Все члены класса должны быть статическими.

1. <strong>Члены класса&#58;</strong>

    - <strong>Обычный класс&#58;</strong> Может содержать как статические, так и нестатические члены (методы, поля, свойства, события).

    - <strong>Статический класс&#58;</strong> Все члены класса должны быть статическими.

1. <strong>Наследование&#58;</strong>

    - <strong>Обычный класс&#58;</strong> Может наследоваться от других классов и может быть базовым классом для других классов.

    - <strong>Статический класс&#58;</strong> Не может наследоваться от других классов и не может быть базовым классом.

1. <strong>Конструкторы&#58;</strong>

    - <strong>Обычный класс&#58;</strong> Может иметь как обычные, так и статические конструкторы.

    - <strong>Статический класс&#58;</strong> Может иметь только статические конструкторы. Обычные конструкторы не допускаются.

:::note[Ссылки для изучения]

1. [Статические классы в C#](https://learn.microsoft.com/ru-ru/dotnet/csharp/programming-guide/classes-and-structs/static-classes-and-static-class-members)
   :::

---

## <strong>В чем разница переопределения метода между ключевыми словами</strong> <code>new</code> <strong>и</strong> <code>override</code><strong>?</strong> [#q-14bee738d69b8143b271feb33a873d2b]

В C# ключевые слова <code>new</code> и <code>override</code> используются для различных целей при работе с методами в производных классах&#58;

{/* prettier-ignore */}
1. <code>new</code>&#58;

    - Скрывает метод базового класса.

    - Используется, когда метод в производном классе имеет ту же сигнатуру, что и метод в базовом классе, но вы хотите, чтобы он не переопределял его, а скрывал.

    - Пример&#58;

        ```csharp
        public class BaseClass
        {
            public void Method() { /* ... */ }
        }

        public class DerivedClass : BaseClass
        {
            public new void Method() { /* ... */ }
        }
        ```

1. <code>override</code>&#58;

    - Переопределяет виртуальный метод базового класса.

    - Используется для изменения поведения метода в производном классе, который был помечен как <code>virtual</code>, <code>abstract</code> или <code>override</code> в базовом классе.

    - Пример&#58;

        ```csharp
        public class BaseClass
        {
            public virtual void Method() { /* ... */ }
        }

        public class DerivedClass : BaseClass
        {
            public override void Method() { /* ... */ }
        }
        ```

Таким образом, <code>new</code> используется для скрытия метода, а <code>override</code> — для переопределения метода.

:::note[Ссылки для изучения]

1. [Ключевые слова new и override в C#](https://learn.microsoft.com/ru-ru/dotnet/csharp/programming-guide/classes-and-structs/knowing-when-to-use-override-and-new-keywords)
   :::

---

## <strong>Какое различие между</strong> <code>const</code> <strong>и</strong> <code>readonly</code><strong>?</strong> [#q-14bee738d69b814689f0f6238810c070]

В C# ключевые слова <code>const</code> и <code>readonly</code> используются для создания неизменяемых значений, но они имеют разные применения и ограничения&#58;

{/* prettier-ignore */}
1. <code>const</code><strong>&#58;</strong>

    - Компилируется как константа времени компиляции.

    - Должен быть инициализирован при объявлении.

    - По умолчанию является статическим (неявно static).

    - Можно использовать только с примитивными типами данных и строками.

    - Пример&#58;

        ```csharp
        public const int ConstValue = 10;
        ```

1. <code>readonly</code><strong>&#58;</strong>

    - Поле readonly присваивается при объявлении или в соответствующем конструкторе. Для ссылочного типа неизменяема ссылка, но сам объект может оставаться изменяемым.

    - Может быть инициализирован во время выполнения.

    - Может быть нестатическим (экземплярным) или статическим.

    - Можно использовать с любыми типами данных.

    - Пример&#58;

        ```csharp
        public readonly int ReadOnlyValue;

        public MyClass(int value)
        {
            ReadOnlyValue = value;
        }
        ```

Таким образом, <code>const</code> используется для значений, известных на этапе компиляции, а <code>readonly</code> — для значений, которые могут быть установлены во время выполнения.

:::note[Ссылки для изучения]

1. [Разница между const и read only](https://stackoverflow.com/questions/55984/what-is-the-difference-between-const-and-readonly-in-c)
   :::

---

## <strong>Разница между структурой и классом. Приведите примеры структур.</strong> [#q-14bee738d69b81d3b992fced030f326b]

В C# структуры и классы имеют ключевые различия&#58;

{/* prettier-ignore */}
1. <strong>Тип данных&#58;</strong>

    - <strong>Структуры (</strong><code>struct</code><strong>)&#58;</strong> Значимые типы (хранят данные непосредственно).

    - <strong>Классы (</strong><code>class</code><strong>)&#58;</strong> Ссылочные типы (хранят ссылку на данные в памяти).

1. <strong>Наследование&#58;</strong>

    - <strong>Структуры&#58;</strong> Не поддерживают наследование, кроме реализации интерфейсов.

    - <strong>Классы&#58;</strong> Поддерживают наследование и могут быть базовыми и производными классами.

1. <strong>Конструкторы&#58;</strong>

    - Структуры могут иметь параметризованные конструкторы, а с C# 10 — и явный public-конструктор без параметров. default(T) по-прежнему обнуляет поля, не вызывая такой конструктор.

    - <strong>Классы&#58;</strong> Могут иметь как параметризованные, так и непараметризованные конструкторы.

1. <strong>Инициализация&#58;</strong>

    - Структуры&#58; default(T) дает значения полей по умолчанию; new T() может вызвать явный конструктор. Локальную переменную нужно определенно присвоить до чтения.

    - <strong>Классы&#58;</strong> Требуют явной инициализации.

#### Примеры структур&#58;

```csharp
public struct Point
{
    public int X;
    public int Y;

    public Point(int x, int y)
    {
        X = x;
        Y = y;
    }
}

public struct Rectangle
{
    public Point TopLeft;
    public Point BottomRight;

    public Rectangle(Point topLeft, Point bottomRight)
    {
        TopLeft = topLeft;
        BottomRight = bottomRight;
    }
}
```

Структуры часто используются для небольших, неизменяемых объектов, таких как координаты, временные отметки и т.д.

:::note[Ссылки для изучения]

1. [Выбор между классом и структурой в C#](https://learn.microsoft.com/ru-ru/dotnet/standard/design-guidelines/choosing-between-class-and-struct)
   :::

---

## <strong>Может ли экземпляр структуры храниться в куче (</strong><code>heap</code><strong>)? Как это сделать?</strong> [#q-14bee738d69b814b9285c4e2e19e8771]

ref передает ссылку на существующее хранилище и сам по себе не перемещает структуру в кучу. Пример boxing&#58; Point p = new Point(1, 2); object boxed = p; — в boxed помещается копия значения.

:::note[Ссылки для изучения]

1. [Может ли структура храниться в heap](https://learn.microsoft.com/en-us/archive/msdn-technet-forums/90b6ae4e-f701-45a1-b708-423e630257e8)
   :::
