Приведение универсального контейнера типа в контейнер наследуемого типа - PullRequest
2 голосов
/ 09 сентября 2011

Если у меня есть два класса:

public class A { }
public class B : A { }

, и я создаю общий контейнер и функцию, которая его принимает:

public void Foo(List<A> lst) { ... }

Я получаю недопустимое преобразование, если я пытаюсь наложитьList<B> в List<A>, и вместо этого нужно передать его следующим образом:

var derivedList = new List<B>();
Foo(new List<A>(derivedList));

Есть ли способ передать List<B> в эту функцию без дополнительных затрат на выделение нового списка,или C # не поддерживает преобразование универсального контейнера производного типа в его базовый тип?

Ответы [ 3 ]

5 голосов
/ 09 сентября 2011

A List<B> просто не a List<A> - в конце концов, вы можете добавить A к List<A>, но не к List<B>.

Если вы используете C # 4 и .NET 4 и , ваш метод Foo действительно должен выполнять итерацию по списку, а затем измените метод на:

public void Foo(IEnumerable<A> lst) { ... }

In.NET 4, IEnumerable<T> является ковариантным в T, что позволяет преобразовывать IEnumerable<B> (включая List<B>) в IEnumerable<A>.Это безопасно, потому что значения выходят только из IEnumerable<A>.

. Для более детального ознакомления с этим вы можете посмотреть видео сеанса, которое я дал на NDC 2010 в рамках Поток видео NDC 2010 .

1 голос
/ 09 сентября 2011

Это невозможно.C # не поддерживает совместную / противоположную дисперсию для конкретных типов, таких как List<T>.Он поддерживает его на интерфейсах, поэтому, если вы переключите Foo на следующую подпись, вы можете избежать выделения

public void Foo(IEnumerable<A> enumerable) { ...
0 голосов
/ 09 сентября 2011

Если вы хотите передать подобные списку вещи подпрограммам, которые собираются их читать, но не записывают, можно определить общий ковариантный IReadableListинтерфейс, так что IReadableList может быть передан в процедуру, ожидающую IReadableList .К сожалению, обычные существующие реализации IList не реализуют ничего подобного, и поэтому единственный способ реализовать один из них - реализовать класс-оболочку (который может принимать IList в качестве параметра), но, вероятно, этого не произойдет.слишком сложно.Такой класс должен также реализовывать неуниверсальный IList, также как доступный только для чтения, чтобы позволить коду оценивать Count без необходимости знать тип элементов в списке.

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

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