Язык C # определяет открытый тип должен быть типом, который является либо аргументом типа, либо универсальным типом, определенным с аргументами неизвестного типа:
Все типы могут быть классифицированы как открытые или закрытые типы. Открытый тип - это тип, который включает параметры типа. Более конкретно:
- Параметр типа определяет открытый тип.
- Тип массива является открытым типом тогда и только тогда, когда его тип элемента является открытым типом.
- Сконструированный тип является открытым типом тогда и только тогда, когда один или несколько его аргументов типа являются открытым типом . Сконструированный вложенный тип является открытым типом тогда и только тогда, когда один или несколько его аргументов типа или аргументы типа содержащего его типа (ов) являются открытым типом.
закрытый тип - это тип, который не является открытым типом.
Следовательно, T
, List
и Dictionary
и Dictionary
все открытые типы ( T
и U
- аргументы типа), тогда как List
и Dictionary
закрыты типы.
Существует связанная концепция: несвязанный универсальный тип - это универсальный тип с неопределенными аргументами типа. Несвязанный тип не может использоваться в выражениях, отличных от typeof ()
, и вы не можете создать его экземпляр или вызвать его методы.Например, Список <>
и Словарь <,>
являются несвязанными типами.
Чтобы прояснить тонкое различие между открытым типом и несвязанным типом:
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
. Во время выполнения ясно, что аргументом типа является System.Int32
. Это делает List
связанным открытым типом.
Во время выполнения вы можете использовать отражение для привязки аргументов типа к неопределенным параметрам типа несвязанных универсальных типов с помощью метода 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
или Dictionary <, string>
.
Просто добавить:
словарь <Строка, т>
(или более точно словарь
) все еще открытый тип.
Пример:
void Foo<T>(Dictionary<string,T> dic) { ... }
Есть три вида родовых типов. Короче говоря, в этом (упрощенном) объявлении:
public class Dictionary<TKey, TValue> : IEnumerable<KeyValuePair<TKey, TValue>>
Словарь
является неограниченным родовым типом.
KeyValuePair
в данном случае является открытым типовым типом . Он имеет некоторые параметры типа, но они уже определены в другом месте (в словаре, в данном случае).
Словарь<строка, int>
будет закрытым построенным типовым типом.
«Открытый универсальный тип» - это просто универсальный тип, для которого еще не указан его тип (например, CargoCrate
). Он становится «закрытым» после присвоения конкретного типа (например, CargoCrate
).
Например, у вас есть что-то вроде этого:
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
, мы теперь называем его закрытым .