Логика и ее применение к коллекциям. Общее и наследование - PullRequest
3 голосов
/ 21 сентября 2008

Все наследуется от объекта. Это основа наследования. Все может быть неявно приведено к наследственному дереву, т. Е.

object me = new Person();

Следовательно, следуя этому логическому заключению, группа людей также будет группой объектов:

List<Person> people = new List<Person>();
people.Add(me);
people.Add(you);
List<object> things = people; // Ooops.

За исключением того, что это не сработает, люди, разработавшие .NET, либо упустили это из виду, либо есть причина, и я не уверен, какая именно. По крайней мере, однажды я столкнулся с ситуацией, когда это было бы полезно, но мне пришлось в конечном итоге использовать неприятный хак (создание подкласса List просто для реализации оператора приведения).

Вопрос в следующем: есть ли причина для такого поведения? Есть ли более простое решение для получения желаемого поведения?

Для справки, я считаю, что ситуация, в которой я хотел такого рода поведения, была общей функцией печати, которая отображала списки объектов, вызывая ToString () и корректно форматируя строки.

Ответы [ 6 ]

5 голосов
/ 21 сентября 2008

ОК, каждый, кто использовал дженерики в .net, должен был столкнуться с этим в тот или иной момент.

Да, интуитивно это должно работать. Нет, в текущей версии компилятора C # это не так.

У Эрика Липперта есть действительно хорошее объяснение этой проблемы (он состоит из одиннадцати частей или чего-то еще, и он изумит вас местами, но он того стоит) Смотри здесь .

редактирование:

выкопал еще одну релевантную ссылку, в этой обсуждается, как java справляется с этим. Смотри здесь

4 голосов
/ 21 сентября 2008

Вы можете использовать linq, чтобы разыграть его:

IEnumerable<Person> oldList = someIenumarable;
IEnumerable<object> newList = oldlist.Cast<object>()
3 голосов
/ 21 сентября 2008

Обходной путь linq хорош. Другой обходной путь, поскольку вы используете тип объекта, - передать список как IEnumerable (не универсальная версия).

Редактировать : C # 4 (в настоящее время бета) поддерживает параметр ковариантного типа в IEnumerable. Хотя вы не сможете напрямую назначить список , вы можете передать свой список методу, ожидающему IEnumerable .

3 голосов
/ 21 сентября 2008

На первый взгляд, это не имеет смысла. Но это так. Посмотрите на этот код:

List<Person> people = new List<Person>();
List<object> things = people; // this is not allowed
// ...
Mouse gerald = new Mouse();
things.add(gerald);

Теперь у нас неожиданно появляется List из Person объектов ... с Mouse внутри!

Это объясняет, почему присвоение объекта типа A<T> переменной типа A<S> недопустимо, даже если S является супертипом T.

2 голосов
/ 01 июня 2009

Хотя то, что вы пытаетесь сделать, действительно протекает логически, на самом деле это функция, которую многие языки не поддерживают изначально. Это то, что называется co / contra variance, что связано с тем, когда и как объекты могут быть неявно преобразованы компилятором из одной вещи в другую. К счастью, C # 4.0 принесет ковариацию и контравариантность на арену C #, и такие неявные приведения, как это, должны быть возможны.

Для подробного объяснения этого может помочь следующее видео Channel9:

http://channel9.msdn.com/shows/Going+Deep/Inside-C-40-dynamic-type-optional-parameters-more-COM-friendly/

1 голос
/ 21 сентября 2008

С помощью методов расширения linq вы можете сделать

IEnumerable<object> things = people.Cast<object>();
List<object> things = people.Cast<object>().ToList();

В противном случае, поскольку вы строго печатаете список, неявное преобразование не допускается.

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