Можно привести общие параметры C#?
Я написал метод с подписью:
private List<ClientItem> ConvertToClientItems(BaseCollection<object> serverItems)
Я пытаюсь назвать это следующим образом:
ConvertToClientItems(approvedSellers);
где approvedSellers
имеет тип BaseCollection<Seller>
- с Seller
будучи классом, который я не могу контролировать.
Разве это не возможно? Visual Studio выдает ошибку, говоря, что не может привести BaseCollection<seller>
в BaseCollection<object>
,
2 ответа
Хорошо, представьте код, который выглядит так:
private List<ClientItem> ConvertToClientItems(BaseCollection<object> serverItems) {
serverItems.Add(new Buyer());
}
Это должно скомпилировать, так как Buyer
является object
,
Тем не менее, если вы передаете BaseCollection<Seller>
Вы только что попытались добавить покупателя в список продавцов.
Таким образом, утверждение
BaseCollection<Seller>
это подтипBaseCollection<object>
только если BaseCollection
гарантирует, что универсальный тип T
используется только в выходных позициях. Приведенный выше пример добавления будет использовать T
в позиции ввода.
Чтобы решить эту проблему, у вас есть следующие варианты:
- Сделайте BaseCollection "ковариантным", добавив ключевое словоout, которое потребует удаления любого
Add
методы. Это, однако, может сделать вашу коллекцию бесполезной. Передайте ковариантный интерфейс методу. Если вам нужно только прочитать
serverItems
передатьIEnumerable
, который уже является ковариантным (и вы упоминаете в комментариях, что BaseCollection уже реализуетIEnumerable
):private List<ClientItem> ConvertToClientItems(IEnumerable<object> serverItems) { // You can only read serverItems here, so we are fine. }
сделать сам метод универсальным
private List<ClientItem> ConvertToClientItems<T>(BaseCollection<T> serverItems) { // This also prevents the evil `Add` call, since you'd need to create // an object of the correct type T first. }
В BaseCollection вы должны сделать T ковариантным, используя ключевое слово "out".
Дополнительная информация http://msdn.microsoft.com/en-us/library/dd233059.aspx.
(IEnumerable работает, потому что он ковариантен.)
public interface BaseCollection<out T>