Home » Дисперсия, инвариантность, ковариация и контравариантность

Дисперсия, инвариантность, ковариация и контравариантность

Вам трудно это понять? Позвольте мне упростить это для вас.

Фото [email protected] на Unsplash

Если тебе так трудно понять, что Инвариантность, Ковариацияи Контравариантность в .NET С# значит, не стыдись этого, ты не один.

Это случилось со мной и многими другими разработчиками. Я даже знаю опытных разработчиков, которые либо не знают о них и используют их, но все еще не могут их достаточно хорошо понять.

Насколько я понимаю, это происходит потому, что каждый раз, когда я натыкаюсь на статью, в которой говорится о Инвариантность, Ковариацияи КонтравариантностьЯ считаю, что он сосредоточен на некоторых технических терминах, а не на том, почему они у нас вообще есть и что мы бы упустили, если бы их не существовало.

Простое объяснение DotNet (.NET) CSharp (C#) Шпаргалка по инвариантности, ковариации и контравариантности.  Передовая практика Кодирования Программирование Разработка программного обеспечения Архитектурная инженерия

Фото Ольги Телаварт на Unsplash, изменено Ахмедом Тареком

2021–11–04

Я заметил это понимание Инвариантность, Ковариацияи Контравариантность поможет вам разобраться в других темах и принять правильные дизайнерские решения. Подробнее об этом вы можете узнать в моей истории Передовой опыт проектирования интерфейсов на .NET C#; Достаточно ли определить IMyInterface? мне тоже нужен IMyInterface?

Простое объяснение DotNet (.NET) CSharp (C#) Шпаргалка по инвариантности, ковариации и контравариантности.  Передовая практика Кодирования Программирование Разработка программного обеспечения Архитектурная инженерия

Фото Тадаса Сара на Unsplash

Определение Microsoft

Если вы проверите документация Microsoft для Инвариантность, Ковариацияи Контравариантность в .NET С#вы найдете такое определение:

В C# ковариация и контравариация обеспечивают неявное преобразование ссылок для типов массивов, типов делегатов и аргументов универсального типа. Ковариация сохраняет совместимость присваиваний, а контравариация меняет ее.

Ты понял? вам это нравится?

Вы можете поискать в Интернете и найти массу ресурсов по этой теме. Вы встретите определения, историю, примеры кода и многое другое, и это не то, что вы найдете в этой истории. Я обещаю вам, что то, что вы увидите здесь, будет другим….

Простое объяснение DotNet (.NET) CSharp (C#) Шпаргалка по инвариантности, ковариации и контравариантности.  Передовая практика Кодирования Программирование Разработка программного обеспечения Архитектурная инженерия

Фото Риса Кентиша на Unsplash

Что они на самом деле?

По сути, Microsoft добавила небольшое дополнение к тому, как вы определяете заполнитель общего типа шаблона, знаменитый .

При определении общего интерфейса вы привыкли следовать шаблону:

public interface IMyInterface<T> {}

После введения ковариации и контравариации вы теперь можете следовать шаблону:

public interface IMyInterface<out T> {}

или

public interface IMyInterface<in T> {}

Узнаете ли вы дополнительное вне и в ?

Вы видели их где-нибудь еще?

Может быть, на знаменитом .NET

public interface IEnumerable<out T>?

или знаменитый .NET

public interface IComparable<in T>?

Microsoft представила новую концепцию, позволяющую компилятору во время разработки следить за тем, чтобы типы объектов, которые вы используете и передаете универсальным членам, не вызывали исключений во время выполнения, вызванных неправильными ожиданиями типов.

Все еще не ясно, да? Просто потерпите… Предположим, что компилятор не применяет никаких ограничений на время разработки, и посмотрим, что произойдет.

Простое объяснение DotNet (.NET) CSharp (C#) Шпаргалка по инвариантности, ковариации и контравариантности.  Передовая практика Кодирования Программирование Разработка программного обеспечения Архитектурная инженерия

Фото Рика Монтейро на Unsplash

Что, если компилятор не применяет никаких ограничений на время разработки?

Чтобы иметь возможность работать над подходящим примером, давайте определим следующее:

Посмотрев на приведенный выше код, вы заметите, что:

  1. Класс А имеет F1() определенный.

  2. Класс Б имеет F1() и F2() определенный.

  3. Класс С имеет F1(), F2() и F3() определенный.

  4. Интерфейс IReaderПисатель имеет Читать() который возвращает объект типа TEntity и Запись (объект TEntity) который ожидает параметр типа TEntity.

Тогда давайте определим ТестReadWriter() метод следующим образом:

Вызов TestReadWriter() при передаче экземпляра IReaderWriter

Это должно работать нормально поскольку мы не нарушаем никаких правил. ТестReadWriter() уже ожидает параметр типа IReaderПисатель.

Вызов TestReadWriter() при передаче экземпляра IReaderWriter

Принимая во внимание предположение, что компилятор не применяет никаких ограничений времени разработки.это значит, что:

  1. параметр.Читать() вернет экземпляр класса А, не Б

  2. Итак есть б на самом деле будет типа А, не Б

  3. Это привело бы к б.F2() линия к неудача как есть б -который на самом деле имеет тип А– не имеет F2() определенный

  4. параметр.Запись() строка в приведенном выше коде ожидает получения параметра типа Анет Б

  5. Итак, вызов параметр.Запись() при передаче параметра типа Б оба бы работать нормально

Следовательно, поскольку в пункте №1 мы ожидаем сбой во время выполнения, тогда мы не можем позвонить ТестReadWriter() с передачей экземпляра IReaderПисатель.

Вызов TestReadWriter() при передаче экземпляра IReaderWriter

Принимая во внимание предположение, что компилятор не применяет никаких ограничений времени разработки.это значит, что:

  1. параметр.Читать() вернет экземпляр класса Снет Б

  2. Итак есть б на самом деле будет типа Снет Б

  3. Это привело бы к б.F2() линия к работать нормально как есть б имел бы F2()

  4. параметр.Запись() строка в приведенном выше коде ожидает получения параметра типа Снет Б

  5. Итак, вызов параметр.Запись() при передаче параметра типа Б бы неудача потому что просто ты не можешь заменить С со своим родителем Б

Следовательно, поскольку в пункте #2 мы ожидаем сбой во время выполнения, тогда мы не можем позвонить ТестReadWriter() с передачей экземпляра IReaderПисатель.

Простое объяснение DotNet (.NET) CSharp (C#) Шпаргалка по инвариантности, ковариации и контравариантности.  Передовая практика Кодирования Программирование Разработка программного обеспечения Архитектурная инженерия

Фото Маркуса Винклера на Unsplash

Теперь давайте проанализируем то, что мы обнаружили к этому моменту:

  1. Вызов ТестReadWriter(IReaderWriter параметр) при передаче экземпляра IReaderПисатель всегда в порядке.

  2. Вызов ТестReadWriter(IReaderWriter параметр) при передаче экземпляра IReaderПисатель было бы хорошо, если бы у нас не было параметр.Читать() вызов.

  3. Вызов ТестReadWriter(IReaderWriter параметр) при передаче экземпляра IReaderПисатель было бы хорошо, если бы у нас не было параметр.Запись() вызов.

  4. Однако, поскольку у нас всегда есть смесь между параметр.Читать() и параметр.Запись()нам всегда придется звонить ТестReadWriter(IReaderWriter параметр) с передачей экземпляра IReaderПисательничего больше.

  5. Пока не…….

Простое объяснение DotNet (.NET) CSharp (C#) Шпаргалка по инвариантности, ковариации и контравариантности.  Передовая практика Кодирования Программирование Разработка программного обеспечения Архитектурная инженерия

Фото Хэла Гейтвуда на Unsplash

Альтернатива

Что, если мы убедимся, что IReaderПисатель интерфейс определяет либо TEntity Чтение() или void Write (объект TEntity)а не то и другое одновременно.

Поэтому, если мы отбросим TEntity Чтение()мы сможем позвонить ТестReadWriter(IReaderWriter параметр) с передачей экземпляра IReaderПисатель или IReaderПисатель.

Аналогично, если мы отбросим void Write (объект TEntity)мы сможем позвонить ТестReadWriter(IReaderWriter параметр) с передачей экземпляра IReaderПисатель или IReaderПисатель.

Это было бы лучше для нас, поскольку было бы менее ограничительно, верно?

Простое объяснение DotNet (.NET) CSharp (C#) Шпаргалка по инвариантности, ковариации и контравариантности.  Передовая практика Кодирования Программирование Разработка программного обеспечения Архитектурная инженерия

Фото Agence Olloweb на Unsplash

Время для некоторых фактов

  1. В реальном мире компилятор во время разработки никогда не позволит вызывать ТестReadWriter(IReaderWriter параметр) с передачей экземпляра IReaderПисатель. Вы получите ошибку компиляции.

  2. Кроме того, компилятор во время разработки не позволял вызывать ТестReadWriter(IReaderWriter параметр) с передачей экземпляра IReaderПисатель. Вы получите ошибку компиляции.

  3. Из пунктов №1 и №2 это называется Инвариантность.

  4. Даже если ты уронишь TEntity Чтение() из IReaderПисатель интерфейс, компилятор во время разработки не позволит вам вызывать ТестReadWriter(IReaderWriter параметр) с передачей экземпляра IReaderПисатель. Вы получите ошибку компиляции. Это связано с тем, что компилятор не будет – неявно сам по себе – просматривать члены, определенные в интерфейсе, и проверять, будет ли он всегда работать во время выполнения или нет. Вам нужно будет сделать это самостоятельно через <в TEntity>. Это действует как ваше обещание компилятору, что все члены интерфейса либо не будут зависеть от TEntity или относиться к этому как к вход, не выход. Это называется Контравариантность.

  5. Аналогично, даже если вы отбросите void Write (объект TEntity) из IReaderПисатель интерфейс, компилятор во время разработки не позволит вам вызывать ТестReadWriter(IReaderWriter параметр) с передачей экземпляра IReaderПисатель. Вы получите ошибку компиляции. Это связано с тем, что компилятор не будет – неявно сам по себе – просматривать члены, определенные в интерфейсе, и проверять, будет ли он всегда работать во время выполнения или нет. Вам нужно будет сделать это самостоятельно через <вне TEntity>. Это действует как ваше обещание компилятору, что все члены интерфейса либо не будут зависеть от TEntity или относиться к этому как к выход, не вход. Это называется Ковариация.

  6. Поэтому, добавив <вне > или <в > делает компилятор менее строгим для удовлетворения наших нужд, а не более строгим, как могли бы подумать некоторые разработчики.

Простое объяснение DotNet (.NET) CSharp (C#) Шпаргалка по инвариантности, ковариации и контравариантности.  Передовая практика Кодирования Программирование Разработка программного обеспечения Архитектурная инженерия

Изображение Harish Sharma с сайта Pixabay

Краткое содержание

На этом этапе вы уже должны понимать всю историю Инвариантность, Ковариацияи Контравариантность. Тем не менее, если кратко подвести итоги, вы можете иметь дело со следующим: шпаргалка:

  1. Смешайте общий тип ввода и вывода => Инвариантность => самые строгие => не могут быть заменены родителями или детьми.

  2. Добавлен <в > => только вход => Контравариантность => сам или заменить родителями.

  3. Добавлен <вне > => только выход => Ковариация => сам или заменить детьми.

Простое объяснение DotNet (.NET) CSharp (C#) Шпаргалка по инвариантности, ковариации и контравариантности.  Передовая практика Кодирования Программирование Разработка программного обеспечения Архитектурная инженерия

Изображение Ахмеда Тарека

Наконец, я оставлю здесь некоторый код, чтобы вы могли его проверить. Это поможет вам больше практиковаться.

Вот и все, надеюсь, вам было так же интересно читать эту статью, как и мне ее писать.

2023-12-28 03:01:25


1703738470
#Дисперсия #инвариантность #ковариация #контравариантность

Read more:  «Стремление возложить на Путина беспрецедентные расходы»

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.