Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > .NET Frameworks (точка нет фреймворки) > C# (си шарп)
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 18.06.2016, 23:01   #1
BadCats
Пользователь
 
Аватар для BadCats
 
Регистрация: 31.01.2016
Сообщений: 67
По умолчанию Generic Типы и UpCast к базовому интерфейсному типу(ковариантность обобщений)

Всем привет, имеется следующий код:
Код:
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()
        {
            Circle circle = new Circle();

            IContainer<Circle> container = new Container<Circle>(circle);

            Console.WriteLine(container.Figure.ToString());

            // Delay.
            Console.ReadKey();
        }
    }
Итак, вкратце - что я понял в данном примере.

В данном примере мы сперва создаем абстрактный класс с именем Shape{}, затем мы создаем конкретный класс с именем Circle - который наследуется от абстрактного класса shape.

далее мы создаем открытый интерфейс с именем IContainer - параметризированный - указателем места заполнения типом Т , и в теле данного интерфейса, мы создаем абстрактное авто-свойство с именем Figure - типа указателя места заполнения типа Т.

Далее vss создаем класс с именем Container - который реализует интерфейс IContainer, который в свою очередь(интерфейс) параметризирован типом места заполнения типом Т.

В теле класса Container мы реализуем абстрактное свойство Figure, и после этого мы создаем конструктор, который принимает один аргумент типа указателя места заполнения типом Т, и в теле этого конструктора мы авто свойству Figure присваиваем значение аргумента данного конструктора нашему свойству.

Далее, в классе Program, в теле метода Main(), мы создаем экземпляр класса Circle - который как мы помним наследуется от абстрактного класса Shape.

На строке:
Код:
IContainer<Circle> container = new Container<Circle>(circle);
- мы создаем переменную с именем container - типа базового интерфейсного типа IContainer, а параметр типа места заполнения типом Т у этого базового интерфейсного типа мы "закрываем" нашим типом Circle.

Условно разделим приведенную ниже строку на две части:

IContainer<Circle> container = new Container<Circle>(circle);

(подчеркнутая - первая часть , жирная - вторая часть)

- в итоге мы ожидаем создаваемый во второй части строки - экземпляр класса Container - ожидаем привести его к базовому интерфейсному типу Icontainer, но в самом созданном экземпляре будет хранится свойство того типа, которым мы "закрываем" место заполнения типом Т при создании данного экземпляра - а т.к в данном случае мы "закрыли" при создании экземпляра типом Circle, то в данном случае внутри данного экземпляра будет храниться свойство Figure типа Circle(а точнее реализация этого свойства из конкретного класса Container наследуемого от интерфейса IContainer)

Вот мой вопрос: с абстрактным классом Shape{} и конкретным классом Circle{} - наследующим его - все понятно.

Затем, кто-нибудь объясните толком и по человечески что такое интерфейс и для чего он нужен (нет, я конечно его изучал, но толком не понял; вот например про делегаты мне простым языком объяснили так - "Делегаты — это способ сделать следующее: взять произвольный кусок кода, упаковать его в объект (экземпляр делегата) и вызвать этот кусок кода в любом месте, куда получится передать ссылку на наш экземпляр делегата." - может это и не совсем правильно, но это понятно!)

С авто свойством, его реализацией и конструктором - ине тоже все понятно.

также не понятно зачем автор курса говорит: "но в самом созданном экземпляре будет хранится свойство" - с какого перепугу? Т.е как я догоадываюсь(но не понимаю навернякка) - в экземпляре хранится то, что переданно в него конструктором(в нашем случае пользовательским) - а т.к аргумент конструктора через ключнвое слово this принимает значение метода set, то косвинно (чере конструктор) мы как бы принимаем в экземпляр значение свойства.

И мой самый главный вопрос также вытекает из "что такое интерфейсы - толком" - непонятно зачем мы передаем конструктору уже готовый экземпляр класса Circle, - т.е неужели мы его(этот экземпляр передаваемый как аргумент конструктора) приводим к типу этого интерфейса.

напоследок вот картинка, на которой я пытался разобраться в ситуации:приложено к теме
Изображения
Тип файла: jpg Безымянный.jpg (40.6 Кб, 128 просмотров)
BadCats вне форума Ответить с цитированием
Старый 19.06.2016, 07:09   #2
p51x
Старожил
 
Регистрация: 15.02.2010
Сообщений: 15,707
По умолчанию

Цитата:
Затем, кто-нибудь объясните толком и по человечески что такое интерфейс и для чего он нужен
В вики же более-менее понятно написано. Это некоторое соглашение о внешнем стыке модуля/объекта/... Например, подъезды это один из интерфесов к дому. Зачем? Для унификации - приходит алгоритм сортировки и ему абсолютно пофиг, что за объект, что в нем и как он себя ведет - ему главное наличие некоторого набора определенных функции (интерфеса для сравнения объектов).

Цитата:
"но в самом созданном экземпляре будет хранится свойство" - с какого перепугу?
Потому что так написали:
Код:
    public class Container<T> : IContainer<T>
    {
        public T Figure { get; set; }
Цитата:
непонятно зачем мы передаем конструктору уже готовый экземпляр класса Circle
Потому что конструктор принимает в качестве аргумента один параметр и его хранит.

Цитата:
т.е неужели мы его(этот экземпляр передаваемый как аргумент конструктора) приводим к типу этого интерфейса.
Нет, посмотрите в код. Container реализует интерфейс и используется его реализация интерфейса.
p51x вне форума Ответить с цитированием
Старый 21.06.2016, 23:28   #3
max_prorok
Форумчанин
 
Регистрация: 06.10.2011
Сообщений: 181
По умолчанию

Кажется p51x, уже ругал за мою речь. И сейчас у вас такие же ошибки.
Цитата:
В данном примере мы сперва создаем абстрактный класс с именем Shape{}, затем мы создаем конкретный класс с именем Circle - который наследуется от абстрактного класса shape.
Правильно говорить не создаете, а описываете. Создаете вы экземпляры класса. В данном примере вы создаете экземпляр по имени circle описанного вами ранее класса.
max_prorok вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Обращение к базовому классу ACE Valery Общие вопросы C/C++ 17 02.01.2013 18:04
Generic C# Sparky Помощь студентам 12 12.10.2012 20:32