В процессе изучения языка C# сталкиваюсь, как и все новички, с трудностями понимания. Изучаю язык на нескольких ресурсах, так как каждую тему собираю по понятным для меня кусочкам.
Очередной босс, которого я не могу пройти - это UpCast/DownCast, который приправлен обобщениями. Сначала всё казалось элементарным, темы проходные: Привёл к нужному типу, скрыл какую-то функциональность, засунул нужный тип в метод и всё отлично. Определил класс/метод/делегат/интерфейс с обобщением, в нужном месте подставил системный тип и готово - вы восхитительны ! На большинстве ресурсов на этих примерах повествование заканчивается, но не на ITVDN. Когда начали подставлять пользовательские типы я поплыл.
Объясните, пожалуйста, на примерах из реального мира, детских аналогиях или подобными методами, зачем это всё ??? Зачем мы приводим к типу интерфеса. а где-то присваиваем объекту производного класса ссылку на базовый ??? Когда закрываем обобщение пользовательским типом - это вообще к-к-комбо для моего мозга. Я получил понимание как это делается, но не знаю для чего и в каких случаях ( буду очень благодарен простым аналогиям ) я должен реализовывать эти возможности языка ??? Я почитал темы на форуме, но так и не смог понять для себя глобальный смысл этого мероприятия.
public abstract class Shape { }
public class Circle: Shape { }
public interface IContainer<T>
{
T Figure { get; set; }
}
public class Container<T> : IContainer<T>
{
public T Figure { get; set; }
public Container(T figure)
{
this.Figure = figure;
}
}
class Program
{
static void Main(string[] args)
{
Circle circle = new Circle();
IContainer<Circle> container = new Container<Circle>(circle);
Console.WriteLine(container.Figure.ToString());
}
}
Вопросы:
1.С какой целью в данном примере мы присваиваем ссылку типа IContainer объекту Container ?
2.Закрывая Т типом Circle, что мы ожидаем получить ?
Я не могу понять какой смысл в " public Circle Figure {get;set;}". Как идёт моя логическая цепочка:"Объекту типа Container присваиваем ссылку типа IContainer( Зачем ?? IConteiner и Container оба содержат только T Figure ). При этом мы закрываем типом Circle ( переходим в класс Container и видим что это отражается на типе свойства Figure и конструкторе. Тут начинается основной затык: public Circle Figure {get;set;} - как свойство Figure может быть типа Circle и что мы можем ему присваивать ??? Вероятно, нет понимания из-за отсутствия наполнения классов какими-либо свойствами, методами чтобы стало ясно какая функциональность добавляется/скрывается при выполненных приведениях и закрытии обобщений тем или иным типом ( на примере указанного выше кода ).
1.С какой целью в данном примере мы присваиваем ссылку типа IContainer объекту Container ?
Например, для того чтобы работать с объектом только как с контейнером. Приведу пример:
Представьте, что ваш Container<T>
- более сложный класс, который предоставляет дополнительный функционал:
Тогда Container<T>
будет примерно таким:
public class Container<T> : IContainer<T>, IStorable<T>, IComparable<T>
{
public T Figure { get; set; }
public Container(T figure)
{
this.Figure = figure;
}
public void Store(T item, string filePath)
{
// Реализация IStorable<T>
}
public int CompareTo(T other)
{
// Реализация IComparable<T>
}
}
И чтобы можно было работать с объектом Container<T>
как с объектом, который можно сохранять в файловой системе, мы сделаем следующее:
IStorable<Circle> shapeToSave = new Container<Circle>(circle);
shapeToSave.Store(...);
2.Закрывая Т типом Circle, что мы ожидаем получить ?
Объекту типа Container присваиваем ссылку типа IContainer...
Наоборот. Переменной типа IContainer<Circle>
мы присваиваем ссылку на объект Container<T>
.
По поводу обобщения. Вот у нас есть свойство:
public T Figure { get; set; }
Компилятор, когда видит строчку
IContainer<Circle> container = new Container<Circle>(circle);
понимает, что нужно создать класс, подобный Container<T>
, где вместо типа T
будет наш Circle
. Поэтому свойство "магическим образом" становится типа Circle
. После этой строчки мы этому свойству можем присваивать только объекты типа Circle
.
Если что-то дополнительно нужно пояснить,отпишите об этом ниже.
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
Учусь запускать методы в потокеПодскажите как запустить метод в потоке, если в методе есть входные параметры?
Нужно ли использовать оператор return в функции, тип возвращаемого значения которой указан как void, или же его просто опускать? В чем разница...
Как правильно перевести в массив байт COM-объект и/или объекты, к классам которым нельзя получить доступ и поставить им атрибут Serializable (например,...