En C, el parámetro "T" se usa a menudo para definir funciones que toman cualquier tipo. Se utilizan para escribir clases y métodos genéricos que pueden funcionar con cualquier tipo de datos, al mismo tiempo que mantienen una estricta seguridad de tipos. Discutiremos cómo funcionan y cómo usarlos.
¿Cómo funciona?
La variable "T" que probablemente haya visto en algunas definiciones de métodos se denomina parámetro de tipo genérico, o simplemente "genérico". Los métodos genéricos que usan T se pueden usar con cualquier tipo, lo que facilita la definición de clases y métodos que no se preocupan por los datos que manejan pero que desean preservarlos.
Por ejemplo, las colecciones hacen uso de genéricos, para que puedan manejar cualquier cosa que el usuario les arroje. No hay una definición diferente para
List
y
List
; en cambio, hay una definición para
List.
En la práctica, se parece a lo siguiente. Aunque esta es una clase y no un método, aún puede pasarle parámetros de tipo usando la sintaxis de paréntesis. Luego, en cualquier lugar donde necesite hacer referencia a algo de este tipo, simplemente sustituya el parámetro en su lugar.

Poner cualquier cosa entre paréntesis le permite usar ese nombre en lugar de un tipo válido, en cualquier parte de la definición de la clase o método que está usando ese parámetro. Si imagina una
GenericList
, en cualquier lugar que escriba
int
como un tipo, en su lugar escribiría
T, y deje que el usuario le diga a esta clase qué tipo usar.
Es realmente así de simple. Para una
GenericList
, el código anterior es funcionalmente equivalente a escribir lo siguiente, aunque debe tenerse en cuenta que esta definición no incluye
GenericList, porque todo lo que está entre paréntesis son parámetros de tipo y las primitivas no se pueden usar como nombres de tipo. Para una clase que no usa ningún parámetro, como esta, se define como siempre sin corchetes.

En realidad, puedes nombrar esta variable T como quieras, aunque es una práctica común comenzar al menos con "T". Si tiene una función que necesita argumentos de varios tipos, puede nombrarlos de manera diferente, como "TOutput" o "TInput". Esto se usa mucho en definiciones de delegados y en diccionarios donde tiene TKey y TValue.

Por supuesto, también puede usar genéricos en métodos, así como interfaces y delegados. Funcionan de la misma manera, e incluso puede pasar el parámetro de tipo como parámetro de tipo a otra función.

Sin embargo, cabe destacar que puede utilizar el parámetro de tipo en los parámetros reales de la función. Aún deberá ponerlo entre paréntesis; de lo contrario, será un tipo no válido, pero puede usar el parámetro en cualquier lugar de la definición de este método.

Son particularmente útiles en delegados, porque puedes usarlos para aceptar funciones con parámetros variables.
Restricciones de tipo
Los genéricos son geniales, pero pueden causar algunos problemas cuando se permite que la función tome cualquier tipo posible que le arrojes. A veces, es mejor poner algunas restricciones de uso.
Esto se hace con la sintaxis
where T:
. La forma más simple de esto es
donde T: ClassName
, lo que asegura que el parámetro T debe ser o derivar del tipo dado
ClassName
Esto permite escribir- polimorfismo seguro, como esta función que toma cualquier tipo de Fruta, y devuelve una
Lista
, en lugar de una
Lista, que sería técnicamente correcto pero pierde valiosa información de tipo.

Puedes ver que si tratamos de usar esta función con cualquier cosa que no sea una fruta, el compilador te gritará.

Más allá de la herencia simple, hay algunas restricciones más útiles:
-
donde T: InterfaceName
– como
T: ClassName pero se asegura de que el argumento tipo implemente la interfaz dada.
-
donde T: class – asegura que el argumento de tipo es un tipo de referencia.
-
donde T: struct – asegura que el argumento de tipo es un tipo de valor no anulable.
-
donde T: notnull – el argumento de tipo debe ser un tipo no anulable.
-
donde T: new() – el argumento de tipo debe poder construirse sin parámetros.
-
donde T: TOther
– el argumento de tipo
T
debe ser, o derivar de, el argumento de tipo
TOther.
Puede especificar varias restricciones en una lista separada por comas.