Неверный аргумент - Интерфейсы, унаследованные, как работает, неявного приведения не имеют.Что дает? - PullRequest
2 голосов
/ 20 декабря 2010

У меня есть функция с подписью

Update(IEnumberable<INotifyPropertyChanging> things)

и класс

doohickey : INotifyPropertyChanging, INotifyPropertyChanging{}

Когда я пытаюсь сделать

List<doohickey> doohickeys = new List<doohickey>();
Update(doohickeys);

Выдается исключение, заявляющее:

cannot convert from 'System.Collections.Generic.List<doohickey>' to 'System.Collections.Generic.IEnumerable<System.ComponentModel.INotifyPropertyChanging>'

Что дает? Doohickey наследует интерфейс INotifyPropertyChanging, а List наследует интерфейс IEnumerable! Почему просто передать объект и ожидать, что он будет брошен, не так?

Я включил ссылки на INotifyPropertyChanging, чтобы указать, что doohickey на самом деле является классом linq-to-sql; в случае, если этот бит контекста имеет значение.

1 Ответ

3 голосов
/ 20 декабря 2010

Это не сработает, поскольку не существует неявного преобразования между List<doohickey> и IEnumerable<NotifyPropertyChanging>. Вам нужно позвонить:

Update(doohickeys.Cast<INotifyPropertyChanging>());

Причиной этого является безопасность типов. В C # 4 к языку была добавлена ​​ко-/ контравариантность, что обычно помогает сделать этот тип преобразований действительным. Однако существуют некоторые ограничения, поскольку соответствующий тип должен быть объявлен со-/ контравариантным и применяется только к интерфейсам и делегатам.

Причина, по которой вы не можете неявно преобразовать List<T> в List<TBase>, состоит в том, что он сделает этот код действительным:

List<T> values = new List<T>();
// add some values...
List<TBase> bases = values;
bases.Add(new TBase());  // Woops. We broke type safety by adding a TBase to a list of T's

Теперь, если вы попытаетесь сделать это, когда values имеет тип IEnumerable<T>, это будет допустимо в C # 4. Это потому, что вы можете только получить значения из IEnumerable<T>, поэтому нам не нужно беспокоиться о добавлении меньших типов. Поэтому IEnumerable<T> является ковариантным и объявляется как:

IEnumerable<out T>

Где out означает «ковариантный». (На самом деле ключевые слова - это лучший способ запомнить, каким образом значения могут идти в типе варианта.

Сопротивление / контравариантность - довольно обширный предмет, , но эта статья хорошо объясняет самые важные части . И если вы хотите узнать больше, у Эрика Липперта есть серия из 11 статей в блоге об этой функции. Эрик - один из языковых дизайнеров.

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