Приведение общей коллекции к базовому типу - PullRequest
6 голосов
/ 12 февраля 2009

У меня есть IList<DerivedClass>, который я хочу привести к ICollection<BaseClass>, но когда я пытаюсь выполнить явное приведение, я получаю null. Возможно ли это сделать без создания и заполнения новой коллекции?

Edit: Поскольку я хочу только читать из коллекции, я переключился на общий метод:

public void PopulateList<BaseClass>(ICollection<T> collection)

Тогда я могу передать это IList<DerivedClass>. Есть ли хороший способ для кэширования этого списка, чтобы я мог обновить его, когда мне нужно. Мое первое желание - использовать:

Object cachedCollection;
Type cachedType;
public void PopulateList<BaseClass>(ICollection<T> collection) {
    cachedCollection = collection;
    cachedType = T;

    // other stuff...
}

private void Refresh() {
    PopulateList<cachedType>(cachedCollection as ICollection<cachedType>);
}

У кого-нибудь есть лучший способ сделать это?

Ответы [ 6 ]

8 голосов
/ 12 февраля 2009

Краткий ответ: «Нет». Вам нужно будет создать новую коллекцию с новым типом BaseClass и заполнить ее.

Если подумать, это имеет смысл. Если бы вы могли просто «привести» вашу коллекцию к BaseClass, вы могли бы вставить в нее что-то, имеющее тип «BaseClass», тем самым принудительно вставив простой объект BaseClass в коллекцию DerivedClass. Это победит цель создания Коллекции с Type-Safety.

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

6 голосов
/ 12 февраля 2009

Это называется ко-дисперсией и, хотя в настоящее время не поддерживается обобщениями в .net, оно будет добавлено в платформу 4.0 (вместе с противоположностью, которая противоречит).

Это отличное видео с PDC 2008 - это сессия по фьючерсам на C #, предоставленная Андерсом Хейлсбергом:

http://channel9.msdn.com/pdc2008/TL16/

4 голосов
/ 12 февраля 2009

Я не думаю, что это возможно, и действительно, это не должно быть:

class BaseClass {}
class DerivedClass : BaseClass {}
class OtherClass : BaseClass {}

void test()
{
  List<DerivedClass> list = new List<DerivedClass>();
  slice(list); //you want to do this
}

void slice(IList<BaseClass> list)
{
  //yikes! adding OtherClass to List<DerivedClass>
  list.Add(new OtherClass());
}
2 голосов
/ 23 февраля 2009

Если вариант .NET 3.5, вы можете использовать метод расширения Cast<T> в System.Core.dll, чтобы получить IEnumerable<T> только для чтения для коллекции:

using System.Linq;
...
private void Refresh() {
  PopulateList( cachedCollection.Cast<cachedType>( ) );
}
2 голосов
/ 12 февраля 2009

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

Проверьте эту ссылку для описания проблемы / ограничения и решения: http://www.25hoursaday.com/weblog/CommentView.aspx?guid=AF7AA888-A227-454C-8687-71FA77186064

Внизу - отличная версия с поддержкой универсального кода.

0 голосов
/ 10 ноября 2015

Вы можете привести каждый элемент к новому итератору:

var collectionOfBase = (collectionOfDerived as IEnumerable).Cast<BaseClass>();
...