Вопрос – Ответ
January 29, 2019

Вопросы на собеседованиях по C# и .Net. На позицию junior/middle. Часть 5.


!!НАШ БЛОГ ПЕРЕЕХАЛ!!

Мы создали свой сайт! Все материалы, опубликованные в этом блоге, переехали туда.

Наш новый сайт maddevelop.ru

А данную статью вы можете найти по ссылке ниже:

https://maddevelop.ru/Textbook/ViewSelectedArticle?textbookName=C%23&sectionName=%D0%A1%D0%BE%D0%B1%D0%B5%D1%81%D0%B5%D0%B4%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%20%D0%BF%D0%BE%20C%23%20%D0%B8%20.NET&subsectionName=%D0%A1%D0%BE%D0%B1%D0%B5%D1%81%D0%B5%D0%B4%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%20%D0%BD%D0%B0%20%D0%BF%D0%BE%D0%B7%D0%B8%D1%86%D0%B8%D1%8E%20junior%2Fmiddle&articleName=%235%20%D0%91%D0%BB%D0%BE%D0%BA%20%D0%B2%D0%BE%D0%BF%D1%80%D0%BE%D1%81%D0%BE%D0%B2%20(%D0%B2%D0%BE%D0%BF%D1%80%D0%BE%D1%81%D1%8B%2031-41)

P.S. движок teletype.in очень странно интерпретирует ссылку, и пришлось вставлять ее полным текстом


Вопрос 31

Какие модификаторы доступа существуют в C#?

Ответ: В C# применяются следующие модификаторы доступа:

  • public: публичный, общедоступный класс или член класса. Такой член класса доступен из любого места в коде, а также из других программ и сборок.
  • private: закрытый класс или член класса. Представляет полную противоположность модификатору public. Такой закрытый класс или член класса доступен только из кода в том же классе или контексте.
  • protected: такой член класса доступен из любого места в текущем классе или в производных классах. При этом производные классы могут располагаться в других сборках.
  • internal: класс и члены класса с подобным модификатором доступны из любого места кода в той же сборке, однако он недоступен для других программ и сборок (как в случае с модификатором public).
  • protected internal: совмещает функционал двух модификаторов. Классы и члены класса с таким модификатором доступны из текущей сборки и из производных классов.
  • private protected: такой член класса доступен из любого места в текущем классе или в производных классах, которые определены в той же сборке.

Вопрос 32

Что такое Boxing и Unboxing?

Ответ: Упаковка представляет собой процесс преобразования типа значения в тип object или в любой другой тип интерфейса, реализуемый этим типом значения. Когда тип значения упаковывается средой CLR, она создает оболочку значения внутри System.Object и сохраняет ее в управляемой куче. Операция распаковки извлекает тип значения из объекта. Упаковка является неявной; распаковка является явной.Понятия упаковки и распаковки лежат в основе единой системы типов C#, в которой значение любого типа можно рассматривать как объект. Ссылка.

Вопрос 33

В чем суть полиморфизма?

Ответ:  Полиморфизм – это различная реализация однотипных действий. Классическая фраза, которая коротко объясняет полиморфизм – «Один интерфейс, множество реализаций». Полиморфизм позволяет писать более абстрактные, расширяемые программы, один и тот же код используется для объектов разных классов, улучшается читабельность кода. Полиморфизм позволяет избавить разработчика от написания, чтения и отладки множества if-else/switch-case конструкций.

Понятие полиморфизма несет за собой еще несколько определений:

  • Виртуальный метод – это метод, который МОЖЕТ быть переопределен в классе-наследнике. Такой метод может иметь стандартную реализацию в базовом классе.
  • Абстрактный метод – это метод, который ДОЛЖЕН быть реализован в классе-наследнике. При этом, абстрактный метод не может иметь своей реализации в базовом классе (тело пустое), в отличии от виртуального.
  • Переопределение метода – это изменение реализации метода, установленного как виртуальный (в классе наследнике метод будет работать отлично от базового класса).

Вопрос 34

Какие типы можно использовать в предложении foreach?

Ответ: Можно использовать типы, которые реализуют интерфейс System.Collections.IEnumerable или System.Collections.Generic.IEnumerable<T>. Либо же к любым типам которые удовлетворяют следующим условиям:

  • включают открытый метод GetEnumerator без параметров с классом, структурой или тип интерфейсом в качестве возвращаемого значения;
  • тип возвращаемого значения метода GetEnumerator должен содержать открытое свойство Currentи открытый метод MoveNext без параметров с типом возвращаемого значения Boolean.

Вопрос 35

Чем отличается event от delegate?

Ответ: Event (событие) — это формализация паттерна наблюдатель на уровне спецификации языка.

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

Именно это ограничение и накладывает событие, в отличие от делегата: это делегат, находящийся под полным контролем объекта, являющегося его собственником.

В следующем примере можно отписать все методы, добавившие себя в делегат хх, простым присвоением null:

xx.Method = null;

С событием так не получится, только если точно знать, какой объект и каким методом на него подписан.

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

xx.Method();

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

Вопрос 36

Может ли класс реализовать два интерфейса, у которых объявлены одинаковые методы? Если да, то каким образом?

Ответ: Если класс реализует два интерфейса, содержащих член с одинаковой сигнатурой, при реализации такого члена в классе оба интерфейса будут использовать этот член в качестве собственной реализации. 

Пример (все вызовы Paint приводят к вызову одного и того же метода)

class Test 
{
    static void Main()
    {
        SampleClass sc = new SampleClass();
        IControl ctrl = sc;
        ISurface srfc = sc;

        // The following lines all call the same method.
        sc.Paint();
        ctrl.Paint();
        srfc.Paint();
    }
}

interface IControl
{  void Paint();  }
interface ISurface
{  void Paint();  }

class SampleClass : IControl, ISurface
{
    // Both ISurface.Paint and IControl.Paint call this method. 
    public void Paint()
    {
        Console.WriteLine("Paint method in SampleClass");
    }
}

// Результат:
// Paint method in SampleClass
// Paint method in SampleClass
// Paint method in SampleClass

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

Например:

public class SampleClass : IControl, ISurface
{
    void IControl.Paint()
    {
        System.Console.WriteLine("IControl.Paint");
    }
    void ISurface.Paint()
    {
        System.Console.WriteLine("ISurface.Paint");
    }
}

Метод класса IControl.Paint доступен только через интерфейс IControl, а ISurface.Paint — только через интерфейс ISurface. Обе реализации метода будут разделены, и ни одна из них не будет доступна в классе напрямую. 

Например:

// Вызов метода Paint через Main

SampleClass obj = new SampleClass();
//obj.Paint();  // Compiler error.

IControl c = obj;
c.Paint();  // Вызываем IControl.Paint из SampleClass.

ISurface s = obj;
s.Paint(); // Вызываем ISurface.Paint из SampleClass.

// Результат:
// IControl.Paint
// ISurface.Paint

Явная реализация также применяется в случаях, когда в каждом из двух интерфейсов объявляются разные члены (например, свойство и метод) с одинаковыми именами:

interface ILeft
{
    int P { get;}
}
interface IRight
{
    int P();
}

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

class Middle : ILeft, IRight
{
    public int P() { return 0; }
    int ILeft.P { get { return 0; } }
}

Вопрос 37

Объясните разницу между System.Array.CopyTo() и System.Array.Clone()?

Ответ: System.Array.CopyTo() - копирует все элементы текущего одномерного массива в заданный одномерный массив.

public void CopyTo (Array array, int index);
Пример:
mySourceArray.CopyTo( myTargetArray, 6 );

System.Array.Clone() - Создает неполную копию Array.

public object Clone ();
Пример
CultureInfo[] arrCIClone = (CultureInfo[]) arrCI.Clone();

Оба метода выполняют неглубокую копию. Неглубокая копия означает, что содержимое нового массива (каждый элемент) содержит ссылки на тот же объект, что и элементы в исходном массиве. Глубокая копия (которая не выполняется ни одним из этих методов) создаст новый экземпляр объекта каждого элемента, что приведет к другому, но идентичному объекту.

Так что разница есть:

1- CopyTo require to have a destination array when Clone return a new array. 
2- CopyTo let you specify an index (if required) to the destination array. 

Вопрос 38

Что такое абстрактный класс? В каком случае вы обязаны объявить класс абстрактным?

Ответ: Абстрактный класс очень похож на обычный класс, он так же содержит обычные методы, свойства, поля. Единственное, что при определении абстрактного класса используется ключевое слова abstract. Главное же отличие его от обычного класса в том, что нельзя использовать стандартный конструктор для создания объекта класса, т.е. так сделать не получится:

Human chelik = new Human();

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

Класс обязательно нужно объявлять как абстрактный когда он содержит абстрактные члены. Источник

Вопрос 39

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

Ответ: В плане определения функционала без конкретной реализации у абстрактных классов и интерфейсов много общего. Часто в программах можно заменять абстрактные классы на интерфейсы и наоборот. Но все же имеются отличия.

Когда лучше использовать абстрактные классы:

  • Для определения общего функционала для родственных объектов
  • Для проектирования большой функциональной единицы, которая содержит обширный базовый функционал
  • Для того, чтобы все производные классы на всех уровнях наследования имели некоторую общую реализацию. При использовании абстрактных классов, для изменения базового функционала во всех наследниках достаточно поменять его в абстрактном базовом классе.
  • Для смены названия или параметра метода интерфейса нужно внести изменения и также во все классы, которые данный интерфейс реализуют.

Когда лучше использовать интерфейсы:

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

Вопрос 40

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

Ответ: Абстрактные классы это класс помеченный ключевым словом abstract. В таком классе мы не можем использовать конструктор для создания объекта класса. В абстрактном классе содержатся абстрактные члены (методы, свойства, индексаторы, события) они не имеют внутренней реализации и выступают в роли интерфейса. Они так же обязаны быть помечены ключевыми словом abstract. При наследовании от абстрактного класса, класс наследник получает все свойства своего класса родителя, а если в родительском классе есть еще и абстрактные члены, то в классе наследнике обязательно их нужно переопределять.

Виртуальный класс, это просто класс в котором есть виртуальные члены (методы, свойства...) Виртуальные члены помечаются модификатором virtual и имеют внутреннюю реализацию, которая может быть переопределена в классе наследнике.

Вопрос 41

Что означает модификатор virtual?

Ответ: Модификатор virtual служит для того, чтобы помечать виртуальные методы или свойства в классе родителя. Виртуальные методы (свойства) - это такие методы, которые мы хотим переопределить в классах наследниках. А чтобы переопределить метод в классе-наследнике, этот метод определяется с модификатором override. Переопределенный метод в классе-наследнике должен иметь тот же набор параметров, что и виртуальный метод в базовом классе.


Ещё больше интересной информации на нашем Telegram канале.

<< К части 4 << ......... >> К части 6 >>

Источники вопросов:

Metanit. Собеседование по C#. Часть 4