Я покопался, почитал, посмотрел видос и вроде бы понял кое-что, поделюсь с вами) Есть принцип подстановки Лисков, в котором говорится следующее: должна существовать возможность использовать объекты производного класса. Это значит, что объекты производного класса должны вести себя согласованно, согласно контракту базового класса. Под контрактом класса понимается ожидаемое от него поведение. Представим, что у родительского и класса наследника разные контракты, то есть, работают они настолько по-разному, что нам придется в коде этот класс наследник обрабатывать по особому, а не как наследника базового класса. Тут же теряется суть наследования - использование класса наследника как базовый класс. Поэтому, когда мы думаем, можно ли сделать какой-то класс наследником другого, нам нужно учитывать не только размытое правило: спроси себя есть между классом-наследником и родительским классом отношение "является". Нам нужно также учитывать, что их контракты будут СОГЛАСОВАННЫМИ. То есть, во время работы программы, мы должны знать, чего ожидать от наследников какого-то класса и не думать о том, что их надо как-то по специальному обрабатывать, ведь у них почему то есть такая функциональность, которая не согласуется с базовым классом. Но, если объекты всё таки связать в одну иерархию хочется, а контракты их разные, это совсем на значит, что сделать это невозможно. А что, есть сделать эти классы immutable, то есть, неизменяемыми? У неизменяемого класса нельзя менять его данные, после того, как он был создан. Если данные менять нельзя, значит, исчезают методы обработки этих данных (зачем методы обработки, если данные неизменяемые?). То есть, мы можем лишь достать что-то оттуда (геттер, например). Что это означает? Это означает, никакой класс не сможет сделать что-то с нашими данными. Не сможет сделать что-то такое, что способно сделать их невалидными. Именно этой же логики следуют правила ковариантности и контравариантности обобщений в языке C#. Так, именно отсутствие изменяемости, позволяет трактовать объект IEnumerable как IEnumerable. Поскольку мы можем лишь достать элемент из последовательности и не можем положить его обратно, то такое преобразование является типобезопасным.
вот есть такие люди как я, которые осилили только 1,2,5 абзацы, не пиши пожалуйста столь длинных комментариев : \ невозможно читать ... это как в примере с игнорированием проблемы ... если ты не можешь игнорировать проблему, декомпозируй её на много маленьких частей, маленькие проблемы игнорировать легче :D продолжай комментарий под своим комментарием, и все люди смогут прочитать всё что их будет интересовать :D а вообще, в последнем абзаце объяснил круто.
@@chpogurt Ключевое слово where позволяет ограничить обобщение. В данном случае интерфейсу ICar в можно указать только Engine и его наследников. Иногда бывает полезно.
@@fj8017 Скажите пожалста - почему так . . . 3:35 . . . в иерархии наследования интерфейс ICar и класс Lada находятся на ОДНОМ УРОВНЕ ??????????. Но ведь тут имеет место НАСЛЕДОВАНИЕ (class Lada : ICar) и поэтому интерфейс БАЗОВЫЙ КЛАСС для класса Lada
Наконец-то нашёл канал, где объясняют что-то, чего я не знаю.) Лайк и подписка.) Очень хочется человеческим и простым языком услышать про асинхронные операции, Task, async - await и прочую дичь. Вроде я понимаю, что они делают, но есть мнение, что я что-то упускаю.)
Ха-ха, автор красава. Разложил для маслят. Если кратко то ковариантность гарантирует type safety для возвращаемых типов, контрвариантность для параметров ну или входных типочков
Слишком опасно и не представляю себе задачу где это бы было необходимо только если кто то уже написал не продуманный не расширяемый код и тебе нужно туда заснуть целого кинконга тогда да
сначала я не понял, потом пошел читать книги и статейки, и потом зашел на этот видос, и все стало понятно, перед просмотром советую прочитать и по практиковаться в студии самим.
Вот что ни говори про Майкрософт, но они умеют учиться на чужих ошибках. В джаве пришлось изобрести мнемонику PECS (Producer Extends Consumer Super), чтобы запомнить когда используется super, а когда extends. А тут всё просто и наглядно, in и out.
На счет того что ковариантность и контрвариантность плюют на строгую типизацию это не совсем так, поскольку как только вы их применяете, на методы интерфейса как раз и налагаются ограничения по поводу возвращаемого типа и типа аргумента. Так что этот вопрос освещен не полностью в частности зачем применяются такие ограничения. Автор либо сам не знает либо очень спешил... куда-то. Видимо друзья перед записью видео позвонили и пригласили пить пиво, а тут ролик еще не готов))
@@РоманКанарейкин Конечно, книги же для тупых. Зачем их вообще пишут? (Я, кстати, уже с момента написания поста на работу устроился и зарабатываю на C#)
@@ithangover589 Только то, что ты пишешь с ошибками и не понимаешь, что написано. Я где-то сказал, что их читать обязательно? Какой ты нах миддл, если ты прочитать внимательно беседу не в состоянии?
Как я поняла, ковариантны если могут использовать наследственность а НЕковариантны, это жестко прописано что слева то и справа? похож на джава... массивы ковариантны, но при получении можно огрести exception, а коллекции НЕковариантны. .. где я?
Единственный вопрос - а науя это надо? Мы же можем использовать ArrayList, в который можем запихнуть объекты разного типа. Останется только достать оттуда элементы, приведя их к изначальному типу.
И при каждом чихе будет происходить упаковка (boxing) и распаковка (unboxing), что ведет к снижению производительности, если данные при этом не ссылочного типа.
я как раз сейчас с этой темой е****, ищу инфу выдают, только такую натянутую, что я просто хочу взять молот и с улыбкой на лице расхерачить ноут. У меня лишь несколько вопросов, нахера это надо? где применять? и как это юзать? Надеюсь в следующем ролики вы опишите данную тему. Спасибо за ролик с меня как всегда лайк.
Ну вот смотри, у нас допустим есть пара машинок с двигателем V8, затем мы добавили еще пару машинок но уже с двигателями V6, V4, и так далее. И у нас тут уже намечается целый автопарк. По умолчанию мы можем создавать коллекции только с машинами определенного двигателя, потому что нас ограничивает инвариантность То есть что то в духе List veightCars = new List(); Но допустим нам надо просто провести какую либо работу со всеми машинами сразу, и при этом нам абсолютно не важно какой именно двигатель установлен на машине. Тут применяется тема из видео - мы тупо используем ковариантность для интерфейса, и теперь все различные машины с разными двигателям (читай как куча разных типов) можем привести к одному единственному типу List cars = new List(); И это позволит нам добавлять в одну коллекцию машины с разными двигателями cars.Add(new Lada()); cars.Add(new Bmw()); cars.Add(new Mercedes()); P.S. Приводим не интерфейс к экземпляру класса, тут правильно читать слева направо - приводим экземпляр класса к типу ICar
Окей, это вроде понятно, но что нам дает обобщенный список интерфейсов, что мы с ними сможем делать? Вообще, что обозначает переменная с типом интерфейс(например, ICar, это же тип, я правильно понимаю?), много где видел, но не понимал сути, поэтому и спросил про конкретную строку) P.S. Спасибо за ремарку, не заметил. И я так понимаю, вы хотели написать справа налево.
Я ничего не понял, но за видео спасибо. Так начнём ещё раз по новому.
Я покопался, почитал, посмотрел видос и вроде бы понял кое-что, поделюсь с вами)
Есть принцип подстановки Лисков, в котором говорится следующее:
должна существовать возможность использовать объекты производного класса. Это значит, что объекты производного класса должны вести себя согласованно, согласно контракту базового класса.
Под контрактом класса понимается ожидаемое от него поведение. Представим, что у родительского и класса наследника разные контракты, то есть, работают они настолько по-разному, что нам придется в коде этот класс наследник обрабатывать по особому, а не как наследника базового класса. Тут же теряется суть наследования - использование класса наследника как базовый класс.
Поэтому, когда мы думаем, можно ли сделать какой-то класс наследником другого, нам нужно учитывать не только размытое правило: спроси себя есть между классом-наследником и родительским классом отношение "является". Нам нужно также учитывать, что их контракты будут СОГЛАСОВАННЫМИ. То есть, во время работы программы, мы должны знать, чего ожидать от наследников какого-то класса и не думать о том, что их надо как-то по специальному обрабатывать, ведь у них почему то есть такая функциональность, которая не согласуется с базовым классом.
Но, если объекты всё таки связать в одну иерархию хочется, а контракты их разные, это совсем на значит, что сделать это невозможно.
А что, есть сделать эти классы immutable, то есть, неизменяемыми? У неизменяемого класса нельзя менять его данные, после того, как он был создан. Если данные менять нельзя, значит, исчезают методы обработки этих данных (зачем методы обработки, если данные неизменяемые?). То есть, мы можем лишь достать что-то оттуда (геттер, например). Что это означает? Это означает, никакой класс не сможет сделать что-то с нашими данными. Не сможет сделать что-то такое, что способно сделать их невалидными.
Именно этой же логики следуют правила ковариантности и контравариантности обобщений в языке C#. Так, именно отсутствие изменяемости, позволяет трактовать объект IEnumerable как IEnumerable. Поскольку мы можем лишь достать элемент из последовательности и не можем положить его обратно, то такое преобразование является типобезопасным.
вот есть такие люди как я, которые осилили только 1,2,5 абзацы, не пиши пожалуйста столь длинных комментариев : \ невозможно читать ...
это как в примере с игнорированием проблемы ... если ты не можешь игнорировать проблему, декомпозируй её на много маленьких частей, маленькие проблемы игнорировать легче :D
продолжай комментарий под своим комментарием, и все люди смогут прочитать всё что их будет интересовать :D
а вообще, в последнем абзаце объяснил круто.
Весьма интересное наблюдение. Спасибо тебе, добрый человек!
Благодарю. Четко и понятно описал. Лайк за комментарий.
@@Buarpa вот оно - проявление клипового мышления
Спасибо большое. Действительно, после вашего комментария всё встало на свои места
Ролики канала экстремального программирования относятся к тем обучающим видео, где тебе нужно замедлять видео, а не ускорять
Я этот ролик раз третий смотрю с промежутками в полгода, кажись, теперь дошло
Я один такой - только подумал что хоть как то начал разбираться, так сразу лопатой по таблу ((
мой мозг выдал ошибку на ключевом слове interface.
Так по жизни.
я поломался когда он к интерфейсам " where T:" начал приписывать
@@chpogurt Ключевое слово where позволяет ограничить обобщение. В данном случае интерфейсу ICar в можно указать только Engine и его наследников. Иногда бывает полезно.
@@fj8017 Скажите пожалста - почему так . . . 3:35 . . . в иерархии наследования интерфейс ICar и класс Lada находятся на ОДНОМ УРОВНЕ ??????????. Но ведь тут имеет место НАСЛЕДОВАНИЕ (class Lada : ICar) и поэтому интерфейс БАЗОВЫЙ КЛАСС для класса Lada
Я ничего не понимаю, что вы говорите, но это так интересно
Благодарю автора за труды!! Посмотрел 2-й раз - кое-что начало проясняться )) Пойду ещё покурю мануалы и вернусь - думаю, будет ещё понятнее ))
Наконец-то нашёл канал, где объясняют что-то, чего я не знаю.) Лайк и подписка.)
Очень хочется человеческим и простым языком услышать про асинхронные операции, Task, async - await и прочую дичь. Вроде я понимаю, что они делают, но есть мнение, что я что-то упускаю.)
Посмотрите канал "Программирование - это просто"
Ха-ха, автор красава. Разложил для маслят. Если кратко то ковариантность гарантирует type safety для возвращаемых типов, контрвариантность для параметров ну или входных типочков
Контрвариантность очень даже нужная штука, в контексте обобщенных делегатов.
Это лучшее объяснение на youtube
Ничего не понятно, но очень интересно
Отдельное спасибо за эту тему, очень много искал где узнать больше о ковариантности и контравариантности. Так держать ;)
Очень понятно и интересно обьясняете. Спасибо за урок
Цитата из видео: "Пока всё логично...", так вот, может и логично, но нихрена не понятно
Слишком опасно и не представляю себе задачу где это бы было необходимо только если кто то уже написал не продуманный не расширяемый код и тебе нужно туда заснуть целого кинконга тогда да
сначала я не понял, потом пошел читать книги и статейки, и потом зашел на этот видос, и все стало понятно, перед просмотром советую прочитать и по практиковаться в студии самим.
И можно видео не смотреть тогда уж :)
Вот что ни говори про Майкрософт, но они умеют учиться на чужих ошибках. В джаве пришлось изобрести мнемонику PECS (Producer Extends Consumer Super), чтобы запомнить когда используется super, а когда extends. А тут всё просто и наглядно, in и out.
На счет того что ковариантность и контрвариантность плюют на строгую типизацию это не совсем так, поскольку как только вы их применяете, на методы интерфейса как раз и налагаются ограничения по поводу возвращаемого типа и типа аргумента. Так что этот вопрос освещен не полностью в частности зачем применяются такие ограничения. Автор либо сам не знает либо очень спешил... куда-то. Видимо друзья перед записью видео позвонили и пригласили пить пиво, а тут ролик еще не готов))
Отличный канал и формат, спасибо, а то от нудного "бубнежа" у некоторых авторов, можно уснуть.
Блин как же много годности
choП is dish? очень интересно, давай еще!
ещё разок и точно пойму.. больше чем 5 реплаев назад.
очень интересно) спасибо))прям по полочкам))
Выглядит и смотрится как краткий пересказ clr via c# Рихтера, то есть очень пиздато. А когда mvvm будет?
Нихуя не понял, но очень интересно.
Сижу я, читаю книжку по С#, смотрю видосики и волосы везде шевелятся. В какую срань же я влез...
Брось книги читать. Программируй, там все на много легче
@@РоманКанарейкин Конечно, книги же для тупых. Зачем их вообще пишут?
(Я, кстати, уже с момента написания поста на работу устроился и зарабатываю на C#)
@@septembercult985 Не одну книгу не прочёл, middle + C#, и что сказать ещё хочешь?
@@ithangover589 Только то, что ты пишешь с ошибками и не понимаешь, что написано. Я где-то сказал, что их читать обязательно?
Какой ты нах миддл, если ты прочитать внимательно беседу не в состоянии?
@@septembercult985 Что? Что ты сейчас написал.
ничего непонятно, но очень интересно
Как я поняла, ковариантны если могут использовать наследственность а НЕковариантны, это жестко прописано что слева то и справа? похож на джава... массивы ковариантны, но при получении можно огрести exception, а коллекции НЕковариантны. .. где я?
Ништяк!!! молодец
Чёткое объяснение! Лучшее, что я видел.
ЗЫ: с сабжем уже знаком, смотрел из великого уважения к каналу.
огонь))) дрьмо что надо)) лойс) пиши еще
упячка?
Щта это было ?? блин видимо я ещё слишком маленький и тупой)
оставлю вкусное на потом , на самый самый кончик
Почему нельзя показать весь написанный код на одном экране? В этом мельтишении слайдов невозможно что-то понять, приходится самому все переписывать.
Интересненько конечно..
мозг плавится... но спасибо за видео
Ну надо же было слово "in" зарезервировать, вот и добавили контрвариантность, чего думать-то :?
Вопрос: почему ты во всех видосах говоришь так, будто улыбаешься?)
ЛОООООООЙС!
2:26 Разве не только массивы ссылочных типов ковариантны?
Никак в голове не уложиться =( жесть блин
Единственный вопрос - а науя это надо? Мы же можем использовать ArrayList, в который можем запихнуть объекты разного типа. Останется только достать оттуда элементы, приведя их к изначальному типу.
И при каждом чихе будет происходить упаковка (boxing) и распаковка (unboxing), что ведет к снижению производительности, если данные при этом не ссылочного типа.
В шарпе ваще дохера наворочено ненужного, чего многие никогда даже не будут использовать, зато мозг будет взрываться при изучении.
@@mrxprojects например?
@@Vadim-wi4by я бы ответил но зае* перечислять
@@mrxprojects ладно. Я просто хотел объяснить зачем нужны те или иные вещи, возможно было бы полезно.
У меня для таких роликов в закладках по c# есть отдельная папочка с именем "*опа".
Еще есть инвариантность )
Абсолютно все классы наследованы от Object, а типы значений неявно расширяют ValueType
сложно!
Да тема не простая, и не факт что на данный момент нужная пока всем подряд :)
ждем выпуска этой темы для маленьких и тупых =D
ну студию-то открой, повтори весь код ручками. ну либо ошибся адресом.
я как раз сейчас с этой темой е****, ищу инфу выдают, только такую натянутую, что я просто хочу взять молот и с улыбкой на лице расхерачить ноут. У меня лишь несколько вопросов, нахера это надо? где применять? и как это юзать? Надеюсь в следующем ролики вы опишите данную тему. Спасибо за ролик с меня как всегда лайк.
пиздец комменты, прикольная аудитория у тебя
MVVM pls )
А вот сейчас больно было
Т.е. клвариантый интерфейс может описывать только методы?
get свойства еще 4:33
а гет_проп и метод - это не одно и то же, если опустить все плюшки с сахаром?
Нихуя не понял, но очень интересно
Тот кто это знает и то не сразу вас поймет. Для обучения есть вполне адекватные уроки.
а когда делегаты(((
Уточка логичней контрвариантности.
Что за утилитка подсвечивает несуществующие типы красным при вводе?
IntelliSens называется
То, что IS эт понятно. Как настроить его так? У меня VS 2017.
Лошарпер ставь
Годно, но жаба душит тратить кучу президентов ради лошарпера для своих приблудопрограмм.
P.S. не Та жаба.
Пожизненый триал в нем есть, юный Джедай.
Я вот совсем маленький и тупой.) Я вот вообще ниче не понял.)))
Бля помню когда то убил на это тему хуеву кучу времени, в результате на практике очень мало встречался с подобным...
Да, есть такое :D
Хотя ковариантность может пригодится, но там и сложного то особо ничего нет :D
пример начиная с 3:03 не понятен :*(
моск сломался(
примеры со сложными цифрами машин в названии, очень сбивают с толку и так сложную тему. Icar834-- toooo much .. короче нету хорошего видео
Лада Лада Лада
Не понимаю, что обозначает эта строка
ICar vEngineCar = lada;
Типа приводим интерфейс к экземпляру класса, но что, блять, это обозначает?
Ну вот смотри, у нас допустим есть пара машинок с двигателем V8, затем мы добавили еще пару машинок но уже с двигателями V6, V4, и так далее. И у нас тут уже намечается целый автопарк. По умолчанию мы можем создавать коллекции только с машинами определенного двигателя, потому что нас ограничивает инвариантность
То есть что то в духе
List veightCars = new List();
Но допустим нам надо просто провести какую либо работу со всеми машинами сразу, и при этом нам абсолютно не важно какой именно двигатель установлен на машине. Тут применяется тема из видео - мы тупо используем ковариантность для интерфейса, и теперь все различные машины с разными двигателям (читай как куча разных типов) можем привести к одному единственному типу
List cars = new List();
И это позволит нам добавлять в одну коллекцию машины с разными двигателями
cars.Add(new Lada());
cars.Add(new Bmw());
cars.Add(new Mercedes());
P.S.
Приводим не интерфейс к экземпляру класса, тут правильно читать слева направо - приводим экземпляр класса к типу ICar
ExtremeCode было б неплохо ещё объяснить почему *вариантности вообще существуют и что же там под капотом происходит когда запиливаем "out" и "in"
Окей, это вроде понятно, но что нам дает обобщенный список интерфейсов, что мы с ними сможем делать?
Вообще, что обозначает переменная с типом интерфейс(например, ICar, это же тип, я правильно понимаю?), много где видел, но не понимал сути, поэтому и спросил про конкретную строку)
P.S. Спасибо за ремарку, не заметил. И я так понимаю, вы хотели написать справа налево.
Почитай про обобщения в интерфейсах, в наших обычных уроках мы не скоро еще дойдем до туда
Лучше пойду учить JavaScript
Ярослав Богачёв, там сплошная ковариантность, динамика - ну его в ****.
Песня
нихера не понял
Контрвариативность применяется как входной метод аргументов обобщений. Применяется часто и вещь очень логичная. Вообщем дизлайк
Порусски пиши, совариантность и противоварианиность.
сложна, сложна, нихуя не панятна
Словил кринж с одного названия
Пацаны, если не сложно, запилите тутор как настроить юнити под фейсбук геймрум, нигде нет информации, явно срубите просмотров и донатов.
Нихуя не понял :(