**Требования:** 1. Запрещается использовать обработку исключительных ситуаций и генерировать исключения. 2. Каждый класс должен быть оформлен в отдельном файле. 3. Придерживайтесь принципа DRY (Don’t repeat yourself). 4. Обязательно наличие комментариев и xml-комментариев. 1. Извлеките интерфейс из класса, описывающего штрихкод. - Создайте тип запись (`record`), реализующего данный интерфейс; - Для различия при выводе информации по тексту штрихкода, обрамлять его символами «\*». - Например, текст «*Hello world!*» должен выводится как «*\* Hello world! \**»; - Сам же текст штрихкода меняться не должен. 2. Извлеките интерфейсную часть из класса товара: - Создайте интерфейс, описывающий товар в полной мере; - У свойства штрихкода замените, его тип на интерфейс. - Классы, у которых присваивают свойству штрихкода новое значение, должны явно использовать штрихкод, по типу запись (Сделать так, как сами это поняли. Возможно вам в этом подскажет псевдокод). 3. Создайте еще один производный класс от производного класса товара: - Запретите дальнейшее наследование от данного класса; - Запретите менять штрихкод данного товара, при нахождении его на витрине: - Штрихкод может меняться при объявлении локальной переменной типа данного класса; - Если штрихкод пытаться менять через интерфейс класса товара, то ничего не получится. 4. Обобщите класс-контейнер (витрину): - Замените хранимый тип контейнера на обобщение; - Извлеките интерфейсную часть класса, при это важно чтобы интерфейсная часть класса сохранила в себе все открытие методы и свойства из класса-контейнера (кроме преобразования к строке); 5. Протестируйте работу программы: - Продемонстрируйте все возможные варианты объявления товара; - Как минимум задействуйте два различных объекта класса-контейнера; - Покажите, как работает перемещение товара из объекта одного класса контейнера в другой и наоборот, и в каких случаях это невозможно. ## Псевдокод ```cs static void TestLab3() { Console.Clear(); var lab3Data = new List<Товароподобный> { new ОбычныйТовар(3000, "ВОЙНА И МИРЬ III", "Л.Н. Толстой", 1867, 300000), new ОбычныйТовар(1000, "ВОЙНА И МИРЬ I", "Л.Н. Толстой", 1863, 1000000), new ОбычныйТовар(2000, "ВОЙНА И МИРЬ II", "Л.Н. Толстой", 1865, 200000) }; var lab3Data2 = new List<КонечныйТовар> { new (5555, "Хранители", "C. Маккоауд", 2008, 2071), new (6666, "Понимание комикса", "A. Шпигельман", 1990, 860) }; ВитринаТовароподобных a1 = 7; a1.Id = 1; // витрина на 7 позиций с 1-м идентификатором ВитринаКонечныхТоваров а2 = (3, 10); // витрина на 3 позиции с 10-м идентификатором foreach (var товар in lab3Data) { a1.Push(товар); } foreach (var товар in lab3Data2) { a1.Push(товар); } a1.OrderByName(); var sample1 = new КонечныйТовар(7777, "Ходячие мертвецы", "P. Кирман", 2003, 2257); var sample2 = new ОбычныйТовар(4000, "ВОЙНА И МИРЬ IV", "Л.Н. Толстой", 1869, 400000); a2[0] = sample1; a1[5] = a2[0]; a1[6] = sample2; a1.Id = 2; // смена ID витрины sample1.Id++; // смена ID товара sample2.Id++; // смена ID товара, будет перезаписан штрихкод // Каждый товар должен правильно отображать штрих код: // - ОбычныйТовар на витрине отображет штрихкод с позицией и ID витрины // - КонечныйТовар, отображает только ID товара, обрамленный * // - Товар sample2, у него штрих код должен выглядеть так: "* 4001 *" Console.WriteLine(al); a2[0] = al[5]; // вам надо починить этот код, чтобы можно было запустить терминал (менять только здесь) Console.WriteLine(a2); } ``` ## Вопросы 1. Чем интерфейс отличается от класса? 2. Можно ли один интерфейс унаследовать от другого? 3. Есть ли в C# множественное наследование? 4. В чем особенность запакованных классов? 5. Чем обобщения в C# отличаются от шаблонов в C++? 6. Почему обобщенный интерфейс класса-контейнера из лабораторной может быть только инвариантным? 7. Сколько вариантов сравнения двух классов между собой можно использовать в C#? Желательно привести примеры.