Почему C# не поддерживает дженерики дженериков (дженерики с параметризованными типами)?
Недавно (возможно, из-за недостатков дизайна) я столкнулся с обычной задачей, когда требовалось собрать коллекцию MyType<T>
где T
не является фиксированным (т. е. несколько различных экземпляров универсальных шаблонов в одной коллекции).
Как это широко предлагается (для таких случаев) абстрактный класс был объявлен:
public abstract class MyType {}
public class MyType<T>: MyType {}
а потом у меня есть коллекция MyType
, Однако для этой коллекции у меня было ограничение не более одного элемента для любого типа T
,
Следовательно, я сделал немного пользовательской реализации ICollection<TBase>
, Я хотел включить туда метод Get<TParam>()
для получения предмета, соответствующего типу TParam
, Позже будет использоваться как:
MyCollection<MyType> collection = new MyCollection<MyType>();
MyType<int> myInt = collection.Get<int>();
Однако я неожиданно обнаружил, что не могу даже объявить это:
public TCustom<TParam> Get<TParam, TCustom<TParam>>() { } //this won't compile
потому что внутренние обобщения (или так называемые "обобщения") не поддерживаются ни C#, ни.NET (я полагаю). Как вы думаете, были ли какие-то конкретные причины таких ограничений (кроме сложности)?
ОБНОВЛЕНИЕ 1. Запрашивается версия компилятора и ошибки компилятора.
Microsoft C#,.NET 3.5 (Visual Studio 2010). Ошибки:
ошибка CS0081: объявление параметра типа должно быть идентификатором, а не типом
ошибка CS0246: не удалось найти тип или имя пространства имен "TCustom" (отсутствует директива using или ссылка на сборку?)
ОБНОВЛЕНИЕ 2. Спросил, нужно ли мне исправить или объяснить, почему. Я действительно хочу знать, ПОЧЕМУ. Но если у вас есть хорошие решения проблемы, добро пожаловать.
ОБНОВЛЕНИЕ 3. На вопрос можно ответить уже в этом сообщении в блоге. Похоже, что команда CLR была под большим давлением, чтобы не усложнять язык.
2 ответа
В этом случае вы можете просто скрыть данные в неуниверсальном словаре:
private Dictionary<Type, object> _Data;
а потом твой Get
метод:
public MyType<TParam> Get<TParam>()
{
return (MyType<TParam>)_Data[typeof(TParam)];
}
Если TParam
типы не связаны, нет общей структуры данных, которая в любом случае обеспечит вам безопасность типов, так зачем даже пытаться?
Зачем именно тебе
public TCustom<TParam> Get<TParam, TCustom<TParam>>() { }
Когда универсальный тип (MyType в вашем случае) известен, вы не можете просто сделать
public MyType<TParam> Get<TParam>() {
return (MyType<TParam>)_items.FirstOrDefault(i => i is MyType<TParam>);
}
Или я что-то упустил?