Что такое "открытый универсальный тип" в.NET?
Я проходил урок Asp.Net MVC и узнал, что для метода, который можно квалифицировать как действие для контроллера,
- У него не должно быть "открытого универсального типа"
Я немного понимаю дженерики и до некоторой степени использую их, но:
- Что такое открытый универсальный тип в.Net.
- Есть ли такая вещь, как закрытый универсальный тип?
- Открытый универсальный тип - это термин, который используется не очень часто. Что используется / путается с этим?
4 ответа
Язык C# определяет открытый тип как тип, который является либо аргументом типа, либо универсальным типом, определенным с аргументами неизвестного типа:
Все типы могут быть классифицированы как открытые или закрытые. Открытый тип - это тип, который включает параметры типа. Более конкретно:
- Параметр типа определяет открытый тип.
- Тип массива является открытым типом тогда и только тогда, когда его тип элемента является открытым типом.
- Созданный тип является открытым типом тогда и только тогда, когда один или несколько его аргументов типа являются открытым типом. Созданный вложенный тип является открытым типом тогда и только тогда, когда один или несколько его аргументов типа или аргументы типа содержащего его типа (типов) являются открытым типом.
Закрытый тип - это тип, который не является открытым типом.
Следовательно T
, List<T>
, а также Dictionary<string,T>
, а также Dictionary<T,U>
все открытые типы (T
а также U
являются аргументами типа) тогда как List<int>
а также Dictionary<string,int>
являются закрытыми типами.
Есть связанная концепция: несвязанный универсальный тип - это универсальный тип с неопределенными аргументами типа. Несвязанный тип не может использоваться в выражениях, отличных от typeof()
и вы не можете создать его экземпляр или вызвать его методы. Например, List<>
а также Dictionary<,>
являются несвязанными типами.
Чтобы прояснить тонкое различие между открытым типом и несвязанным типом:
class Program {
static void Main() { Test<int>(); }
static void Test<T>() {
Console.WriteLine(typeof(List<T>)); // Print out the type name
}
}
Если вы запустите этот фрагмент, он распечатает
System.Collections.Generic.List`1[System.Int32]
которое является названием CLR для List<int>
, Во время выполнения ясно, что аргумент типа System.Int32
, Это делает List<T>
связанный открытый тип.
Во время выполнения вы можете использовать отражение, чтобы связать аргументы типа с неопределенными параметрами типа несвязанных универсальных типов с помощью Type.MakeGenericType
метод:
Type unboundGenericList = typeof(List<>);
Type listOfInt = unboundGenericList.MakeGenericType(typeof(int));
if (listOfInt == typeof(List<int>))
Console.WriteLine("Constructed a List<int> type.");
Вы можете проверить, является ли тип несвязанным универсальным типом (определение универсального типа), из которого вы можете создать связанные типы с помощью Type.IsGenericTypeDefinition
свойство:
Console.WriteLine(typeof(Dictionary<,>).IsGenericTypeDefinition); // True
Console.WriteLine(typeof(Dictionary<int,int>).IsGenericTypeDefinition); // False
Чтобы получить несвязанный тип из составного типа во время выполнения, вы можете использовать Type.GetGenericTypeDefinition
метод.
Type listOfInt = typeof(List<int>);
Type list = listOfInt.GetGenericTypeDefinition(); // == typeof(List<>)
Обратите внимание, что для универсального типа вы можете иметь либо полностью несвязанное определение типа, либо полностью связанное определение. Вы не можете связать некоторые параметры типа и оставить другие не связанными. Например, вы не можете иметь Dictionary<int,>
или же Dictionary<,string>
,
"Открытый универсальный тип" - это просто универсальный тип, для которого еще не указан тип (например, CargoCrate<T>
). Он становится "закрытым" после назначения конкретного типа (например, CargoCrate<Widget>
).
Например, скажем, у вас есть что-то вроде этого:
public class Basket<T> {
T[] basketItems;
}
public class PicnicBlanket<T> {
Basket<T> picnicBasket; // Open type here. We don't know what T is.
}
// Closed type here: T is Food.
public class ParkPicnicBlanket : PicnicBlanket<Food> {
}
Вот, picnicBasket
Тип открыт: еще ничего не назначено T
, Когда вы делаете конкретный PicnicBlanket с определенным типом - например, написав PicnicBlanket<Food> p = new PicnicBlanket<Food>()
- теперь мы называем это закрытым.
Просто добавить:
Dictionary<string, T>
(или точнее Dictionary<string,>
) все еще открытый тип.
Пример:
void Foo<T>(Dictionary<string,T> dic) { ... }
Есть три вида общих типов. Короче говоря, в этом (упрощенном) объявлении:
public class Dictionary<TKey, TValue> : IEnumerable<KeyValuePair<TKey, TValue>>
Dictionary<TKey, TValue>
является неограниченным универсальным типом.KeyValuePair<TKey, TValue>
в данном случае это открытый сконструированный универсальный тип. У него есть некоторые параметры типа, но они уже определены в другом месте (в данном случае в словаре).Dictionary<string, int>
будет закрытым сконструированным универсальным типом.