Что такое "открытый общий тип" в .NET?

Я прошел урок ASPP MVP и узнал, что для метода, который можно квалифицировать как действие для контроллера,

  • Он не должен иметь "открытый общий тип"

Я понимаю несколько дженериков и использую их в некоторой степени, но:

  • Что такое открытый общий тип в .Net.
  • Есть ли такая вещь, как закрытый общий тип?
  • Открытый общий тип - это термин, который не используется очень часто. Что используется/смешивается с ним?

Ответ 1

Язык С# определяет открытый тип как тип, который либо является аргументом типа, либо общим типом, определенным с неизвестными аргументами типа:

Все типы могут быть классифицированы как открытые типы или закрытые типы. Открытый тип - это тип, который включает параметры типа. Более конкретно:

  • Параметр типа определяет открытый тип.
  • Тип массива является открытым типом тогда и только тогда, когда его тип элемента является открытым типом.
  • Созданный тип является открытым типом тогда и только тогда, когда один или несколько его аргументов типа являются открытым типом. Построенный вложенный тип является открытым типом тогда и только тогда, когда один или несколько его аргументов типа или аргументы типа его содержащего типа (ов) являются открытым типом.

Закрытый тип - это тип, который не является открытым.

Поэтому 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 property:

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>.

Ответ 2

Просто добавьте:

Dictionary<string, T> (точнее, Dictionary<string,>) все еще является открытым типом.

Пример:

void Foo<T>(Dictionary<string,T> dic) { ... }

Ответ 3

"Открытый общий тип" - это всего лишь общий тип, который еще не задал свой тип (например, 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>() - мы теперь называем его закрытым.

Ответ 4

Существует три типа общих типов. Короче говоря, в этом (упрощенном) объявлении:

public class Dictionary<TKey, TValue> : IEnumerable<KeyValuePair<TKey, TValue>>
  • Dictionary<TKey, TValue> - неограниченный общий тип.

  • KeyValuePair<TKey, TValue> - это в данном случае открытый построенный общий тип. Он имеет некоторые параметры типа, но они уже определены в другом месте (в этом словаре в словаре).

  • Dictionary<string, int> будет закрытым построенным общим типом.