Что значитимею в виду? - PullRequest
       5

Что значитимею в виду?

25 голосов
/ 30 ноября 2011

Решарпер предложил изменить с

interface IModelMapper<TFrom, TTo>
{
    TTo Map(TFrom input);
}

в

interface IModelMapper<in TFrom, out TTo>

Итак, я немного разбираюсь и закончу читать эту статью (найдена в статье Wikipedia ) и еще несколько Google.

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

Более конкретно, почему я должен принять это?

Ответы [ 2 ]

48 голосов
/ 30 ноября 2011

Итог: Решарпер изучил ваш тип и обнаружил, что TFrom может использоваться контравариантно, а TTo ковариантно. Принятие рефактора позволит вам использовать эти типы с большей гибкостью, как описано ниже. Если это может иметь значение для вас, примите это.

Обратите внимание, однако, что принятие этого рефактора наложит ограничения на использование этих типов в будущем . Если вы когда-нибудь напишите метод, который принимает TTo в качестве параметра, вы получите ошибку компилятора, поскольку ковиариантные типы не могут быть прочитаны. И то же самое для TFrom: вы никогда не сможете иметь метод, который возвращает этот тип или имеет параметр out этого типа.


Это говорит о том, что TFrom является контравариантным, а TTo ковариантным. Эти функции были недавно добавлены в C #

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

IEnumerable<T> является хорошим примером ковариации типов. Поскольку элементы в IEnumerable<T> являются только для чтения , вы можете установить для него что-то более конкретное:

IEnumerable<object> objects = new List<string>();

Подумайте, что может произойти , если (гипотетически) вам разрешено делать это для коллекций, которые были прочитаны / записаны:

List<object> objects = new List<string>();
objects.Add(new Car());
//runtime exception

Чтобы быть ковариантным по типу, универсальный параметр должен использоваться строго только для чтения ; оно должно быть только когда-либо записано из из типа и никогда не должно читаться в (отсюда и ключевые слова). Вот почему пример IEnumerable<T> работает, а пример List<T> - нет. Между прочим, массивы do поддерживают ковариацию типов (так как я полагаю, что Java это делает), и поэтому такая же ошибка времени выполнения возможна с массивами.

Тип контравариантности означает обратное. Для поддержки контравариантности типа универсальный параметр должен читаться только в и никогда не записываться из . Это позволяет заменять менее конкретные типы в.

Action<T> является примером типа контрава:

Action<object> objAction = (o => Console.WriteLine(o.ToString()));
Action<string> strAction = objAction;
strAction("Hello");

strAction объявляется как строковый параметр, но работает нормально, если вы подставляете тип объекта. Будет передана строка, но если делегат, с которым он настроен работать, решит рассматривать его как объект, то пусть будет так. Никакого вреда не сделано.

Для полноты Func<T> - обратный случай Action<T>; здесь T только возвращается, поэтому оно ковариантно:

Func<string> strDelegate =  () => "Hello";
Func<object> myObjFunc = strDelegate;
object O = myObjFunc();

myObjectFunc кодируется для возврата объекта. Если вы установите для него что-то, что возвращает строку, то, опять же, никакого вреда не будет.

2 голосов
/ 30 ноября 2011

В качестве примера того, как этот выбор может повлиять на ваше приложение, предположим, что у вас есть тип CustomerAddressMapper, который реализует IModelMapper<Customer, Address[]>, и другой SupplierAddressMapper, который реализует IModelMapper<Supplier, Address[]>. Типы Customer и Supplier совместно используют базовый класс Company, но их адресная логика отличается, поэтому нам нужны отдельные типы для обработки этого.

Теперь предположим, что у вас есть метод, который принимает IMapper<Company, Address[]>. До противоречивости интерфейса вы не смогли бы передать экземпляры CustomerAddressMapper или SupplierAddressMapper этому методу. Теперь, если вы используете модификатор in для параметра типа TFrom, вы можете.

Кроме того, из-за ковариации параметра TTo вы также можете передать CustomerAddressMapper методам, которые требуют IMapper<Customer, object>.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...