Перейти к содержимому
шпаргалка.
Esc
навигацияоткрыть⌘Jпредпросмотр
На этой странице

Классы и интерфейсы

Все темы С# Developer

Что такое класс?

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


Чем отличается класс от абстрактного класса?

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

  • Классы:

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

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

  • Абстрактные классы:

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

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


Чем отличается абстрактный класс от интерфейса? Для чего нужны интерфейсы и какие задачи они выполняют?

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

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

  1. Наследование:
    • Абстрактный класс: Класс может наследоваться только от одного абстрактного класса.

    • Интерфейс: Класс может реализовывать множество интерфейсов.

  2. Реализация методов:
    • Абстрактный класс: Может содержать как абстрактные методы (без реализации), так и методы с реализацией.

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

  3. Полиморфизм:
    • Абстрактный класс: Поддерживает полиморфизм через виртуальные методы и абстрактные методы.

    • Интерфейс: Поддерживает полиморфизм через методы интерфейса, которые должны быть реализованы в классе.

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

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

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

  1. Поддержки полиморфизма: Позволяет использовать разные классы через общий интерфейс, обеспечивая гибкость и расширяемость кода.

  2. Многоразовости кода: Класс может реализовывать несколько интерфейсов, что позволяет комбинировать функциональность из разных источников.

  3. Снижения связности кода: Позволяет писать более гибкий и тестируемый код. Интерфейсы способствуют инверсии управления (IoC) и внедрению зависимостей (DI).

  4. Упрощения тестирования: Интерфейсы облегчают создание мок-объектов для юнит-тестирования.

Пример использования интерфейса:

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();
        }
    }
}

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


Какие вы знаете модификаторы доступа?

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

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

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

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

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

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

Дополнительно в C# 7.2 был введен модификатор private protected:

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

В чем разница между обычным классом и статическим?

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

  1. Экземпляры:
    • Обычный класс: Может создавать экземпляры (объекты) с использованием оператора new.

    • Статический класс: Нельзя создавать экземпляры. Все члены класса должны быть статическими.

  2. Члены класса:
    • Обычный класс: Может содержать как статические, так и нестатические члены (методы, поля, свойства, события).

    • Статический класс: Все члены класса должны быть статическими.

  3. Наследование:
    • Обычный класс: Может наследоваться от других классов и может быть базовым классом для других классов.

    • Статический класс: Не может наследоваться от других классов и не может быть базовым классом.

  4. Конструкторы:
    • Обычный класс: Может иметь как обычные, так и статические конструкторы.

    • Статический класс: Может иметь только статические конструкторы. Обычные конструкторы не допускаются.


В чем разница переопределения метода между ключевыми словами new и override?

В C# ключевые слова new и override используются для различных целей при работе с методами в производных классах:

  1. new:

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

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

    • Пример:

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

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

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

    • Пример:

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

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


Какое различие между const и readonly?

В C# ключевые слова const и readonly используются для создания неизменяемых значений, но они имеют разные применения и ограничения:

  1. const :
    • Компилируется как константа времени компиляции.

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

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

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

    • Пример:

      public const int ConstValue = 10;
  2. readonly :
    • Поле readonly присваивается при объявлении или в соответствующем конструкторе. Для ссылочного типа неизменяема ссылка, но сам объект может оставаться изменяемым.

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

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

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

    • Пример:

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

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


Разница между структурой и классом. Приведите примеры структур.

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

  1. Тип данных:
    • Структуры (struct): Значимые типы (хранят данные непосредственно).

    • Классы (class): Ссылочные типы (хранят ссылку на данные в памяти).

  2. Наследование:
    • Структуры: Не поддерживают наследование, кроме реализации интерфейсов.

    • Классы: Поддерживают наследование и могут быть базовыми и производными классами.

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

    • Классы: Могут иметь как параметризованные, так и непараметризованные конструкторы.

  4. Инициализация:
    • Структуры: default(T) дает значения полей по умолчанию; new T() может вызвать явный конструктор. Локальную переменную нужно определенно присвоить до чтения.

    • Классы: Требуют явной инициализации.

Примеры структур:

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;
    }
}

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


Может ли экземпляр структуры храниться в куче (heap)? Как это сделать?

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

Эта страница была полезной?