Hasta ahora, en la construcción de nuestros Generics, hemos dejado plena
libertad para el consumidor, tanto si somos nosotros mismos, o si es algún
usuario de alguna de nuestras librerías, de poder asignar el tipo que mejor le
viniera dentro de nuestros parámetros de tipo. Esto en ocasiones, puede ser
contraproducente para su uso, y lo que es peor puede limitarnos en demasía a la
hora de realizar un desarrollo. Las restricciones dentro de Generics nos pueden ayudar a solventar
todos estos problemas.
- · Generics
Cuando definimos nuestras clases, métodos genéricos, podemos
aplicar restricciones al argumento ‘T’
introducido.
Si vemos el ejemplo del primer post
de Generics:
Nuestro parámetro de tipo ‘T’, no tiene ningún tipo de restricción por lo que a la hora de
hacer la llamada la podríamos realizar introduciendo cualquier tipo del CLR. Si inspeccionamos cualquiera de
los parámetros mediante el intellisense,
veremos que los métodos que nos proporciona son los relacionados con el tipo object, tipo base del CLR.
Si ponemos un poco de coherencia al método, atendiendo al
nombre del mismo, CambiarValores,
una buena idea sería restringir su uso solo para tipos por valor,
deshabilitando los tipos por referencia, ya que estos cambiarían la dirección
de memoria a la que apuntan, haciendo un poco confuso el uso del mismo.
Para lograr esto, utilizaremos la palabra reservada where al finalizar la definición del
método y antes de las llaves, de la siguiente forma:
Con esto le estamos indicando al método que los tipos
válidos para el parámetro de tipo, solo podrán ser tipos por valor (struct).
Como podemos apreciar en el pantallazo, la primera llamada
con el tipo int (struct) es completamente válida para
el compilador, mientras la segunda de tipo string
(class) es señalada como error, ya
que no es una estructura (non-nullable).
Tipos de restricción
- Where T: struct .- El tipo de argumento debe de ser un tipo por valor (struct).
- Where T: class .- El tipo de argumento debe de ser un tipo por referencia (class).
- Where T: new() .- El tipo de argumento debe tener un constructor sin parámetros. Si este tipo se usa con más de una restricción debe de ir indicado en último lugar.
- Where T: <base class name> .- El tipo de argumento debe de derivar de la clase especificada.
- Where T: <interface name> .- El tipo de argumento debe implementar la interfaz especificada.
- Where T: U .- El tipo de argumento T debe de derivar del argumento U.
Puede existir más de un tipo de restricción, como en el
ejemplo siguiente:
Observaciones de restricciones de
clase e interfaz
Cuando coges experiencia en la construcción con generics, al desarrollar un método
genérico, no sueles predecir de primeras el añadirle ningún tipo de
restricción, y terminas dándote cuenta de que esta es necesaria cuando tienes
la necesidad acceder a una serie de métodos o propiedades de un ‘tipobase’ como mínimo. Esto se ve
claro cuando accedes a los miembros de alguno de nuestros parámetros del método
genérico en desarrollo, y te encuentras solo con los 4 miembros de tipo object disponibles, que no te sirven
absolutamente par nada. Esto nos da la pista de que tenemos que realizar la
restricción al ‘tipo base’ deseado, para que el intellisense nos muestre los miembros que necesitamos
disponibles.
Lo podemos ver en el siguiente ejemplo, en el que partimos
de la clase base Animal:
No hay comentarios :
Publicar un comentario