148

I was going through Asp.Net MVC lesson and learned that, for a method to qualify as an action for a controller,

  • It must not have an "open generic type"

I understand generics somewhat and use them to some extent, but:

  • What is an open generic type in .Net.
  • Is there such a thing as a closed generic type?
  • Open generic type is a term not used very often. What is used / confused with it ?
abatishchev
  • 98,240
  • 88
  • 296
  • 433
Asad
  • 21,468
  • 17
  • 69
  • 94

4 Answers4

238

The C# language defines an open type to be a type that's either a type argument or a generic type defined with unknown type arguments:

All types can be classified as either open types or closed types. An open type is a type that involves type parameters. More specifically:

  • A type parameter defines an open type.
  • An array type is an open type if and only if its element type is an open type.
  • A constructed type is an open type if and only if one or more of its type arguments is an open type. A constructed nested type is an open type if and only if one or more of its type arguments or the type arguments of its containing type(s) is an open type.

A closed type is a type that is not an open type.

Therefore T, List<T>, and Dictionary<string,T>, and Dictionary<T,U> are all open types (T and U are type arguments) whereas List<int> and Dictionary<string,int> are closed types.

There's a related concept: An unbound generic type is a generic type with unspecified type arguments. An unbound type can't be used in expressions other than typeof() and you can't instantiate it or call its methods. For instance, List<> and Dictionary<,> are unbound types.

To clarify the subtle distinction between an open type and an unbound type:

class Program {
   static void Main() { Test<int>(); }
   static void Test<T>() {
      Console.WriteLine(typeof(List<T>)); // Print out the type name
   }
}

If you run this snippet, it'll print out

System.Collections.Generic.List`1[System.Int32]

which is the CLR name for List<int>. It's clear at runtime that the type argument is System.Int32. This makes List<T> a bound open type.

At runtime, you can use reflection to bind type arguments to unspecified type parameters of unbound generic types with the Type.MakeGenericType method:

Type unboundGenericList = typeof(List<>);
Type listOfInt = unboundGenericList.MakeGenericType(typeof(int));
if (listOfInt == typeof(List<int>))
     Console.WriteLine("Constructed a List<int> type.");

You can check whether a type is an unbound generic type (generic type definition) from which you can construct bound types with the Type.IsGenericTypeDefinition property:

Console.WriteLine(typeof(Dictionary<,>).IsGenericTypeDefinition); // True
Console.WriteLine(typeof(Dictionary<int,int>).IsGenericTypeDefinition); // False

To get the unbound type from a constructed type at runtime, you can use the Type.GetGenericTypeDefinition method.

Type listOfInt = typeof(List<int>);
Type list = listOfInt.GetGenericTypeDefinition(); // == typeof(List<>)

Note that for a generic type, you can either have a completely unbound type definition, or a completely bound definition. You can't bind some type parameters and leave others unbound. For instance, you can't have Dictionary<int,> or Dictionary<,string>.

Community
  • 1
  • 1
Mehrdad Afshari
  • 414,610
  • 91
  • 852
  • 789
  • 12
    +1 great info - I learned something new today. I knew that List<> was a generic type, but now I know the correct technical term. – IAbstract Jan 31 '10 at 20:34
  • 3
    You *can* actually partially close a generic type by providing a type argument that is itself an open generic type. However, this is a dead end. The framework doesn't officially recognize this partial state, treating it as neither closed nor open, and so it doesn't allow you to do anything useful with it. – Chris Ammerman Mar 16 '10 at 21:34
  • 1
    great explanation as to difference between open type and unbound type - didn't know before! – nawfal May 14 '13 at 05:08
  • 2
    I agree with @ChrisAmmerman. For example the type `Dictionary` that you claim we can't have, is more or less constructed by `typeof(Dictionary<,>).MakeGenericType(typeof(int), typeof(Dictionary<,>).GetGenericArguments()[1])`. But maybe you just meant to say that C# does not allow the syntax `Dictionary` so we have to create it manually like I did here. – Jeppe Stig Nielsen Sep 13 '13 at 20:58
  • ... And on the [doc page for `IsGenericType`](http://msdn.microsoft.com/en-us/library/system.type.isgenerictype.aspx), in the *Examples* section's C# code, they regard in a more elegant way a type ``Base`2[System.String,V]`` where one type parameter is substituted with a concrete type and another one is substituted with a parameter `V`. – Jeppe Stig Nielsen Sep 14 '13 at 07:37
18

An "open generic type" is just a generic type that doesn't yet have its type specified (e.g., CargoCrate<T>). It becomes "closed" once a concrete type has been assigned (e.g. CargoCrate<Widget>).

For example, say you have something like this:

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> {
}

Here, picnicBasket's type is open: nothing's yet been assigned to T. When you make a concrete PicnicBlanket with a specific type -- for example, by writing PicnicBlanket<Food> p = new PicnicBlanket<Food>() -- we now call it closed.

John Feminella
  • 303,634
  • 46
  • 339
  • 357
14

Just to add:

Dictionary<string, T> (or more precisely Dictionary<string,>) is still an open type.

Example:

void Foo<T>(Dictionary<string,T> dic) { ... }
leppie
  • 115,091
  • 17
  • 196
  • 297
  • 2
    Upon looking up the spec, I'm seeing that you're right. I thought the "generic type definition" is the same thing as "open type" in the spec but apparently, the spec calls a type parameter and `List` open types and the `List<>` an unbound type. Clarifying my answer. +1 – Mehrdad Afshari Jan 31 '10 at 21:41
11

There are three kinds of generic types. To make it short, in this (simplified) declaration:

public class Dictionary<TKey, TValue> : IEnumerable<KeyValuePair<TKey, TValue>>
  • Dictionary<TKey, TValue> is an unbounded generic type.

  • KeyValuePair<TKey, TValue> is, in this case, an open constructed generic type. It has some type parameters, but they are already defined elsewhere (in Dictionary, in this case).

  • Dictionary<string, int> would be a closed constructed generic type.

Gorpik
  • 10,940
  • 4
  • 36
  • 56