**Требования:**
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#? Желательно привести примеры.