2009-12-03 16 views
13

Escribo una clase genérica de la siguiente manera.¿Por qué la firma de clase genérica requiere especificar new() si el tipo T necesita creación de instancias?

public class Foo<T> : 
    where T : Bar, new() 
{ 
    public void MethodInFoo() 
    { 
     T _t = new T(); 
    } 
} 

Como se puede ver el objeto _t de tipo T se crea una instancia en tiempo de ejecución. Para admitir la creación de instancias del tipo genérico T, el lenguaje me obliga a poner new() en la firma de la clase. Estoy de acuerdo con esto si Bar es una clase abstracta, pero ¿por qué tiene que ser así si Bar estándar no es una clase abstracta con un constructor público sin parámetros?

El compilador solicita el siguiente mensaje si no se encuentra new().

No se puede crear una instancia del tipo de variable de 'T', ya que no tiene el nuevo() restricción

+0

gracias a todos por sus respuestas. el contenido de la respuesta fue realmente bueno para una lluvia de ideas sobre el tema de la pregunta. –

Respuesta

22

Debido a que normalmente no es una suposición de que el parámetro de plantilla necesita ser [no abstracta y] construible [a través de un constructor público sin parámetros] para que un Tipo coincida con la definición del parámetro de la plantilla.

Hasta que se agrega una restricción :new() en la plantilla:

  • El compilador no le permitirá construir un T
  • El compilador le permiten ajustar las T con tipos abstractos o tipos sin un constructor sin parámetros pública

El bit :Bar es ortogonal y significa:

  • No permita que las personas coinciden en contra de tipos que no se derivan de [o son] Bar
  • Let Me echaron T s a Bar o tipos derivados de Bar dentro del cuerpo
  • Voy a llamar pública e in- métodos internos alcance de Bar en un T
+3

No me gusta la fraseología "constructor por defecto", ya que puede no estar claro algunas circunstancias. Lo diría más como: Añadiendo ', new()' obliga al código de usuario a usar un argumento de tipo genérico que presenta un constructor * no-argument *. – Romain

+1

@Romain: MSDN se refiere a él como un "constructor público sin parámetros". http://msdn.microsoft.com/en-us/library/d5x73970.aspx – LukeH

+0

Corregido la pregunta! Nunca me di cuenta de esto. Gracias por corregir. –

3

Tal vez porque si no se incluye la restricción new() continuación T podrían legítimamente ser una subclase de Bar no tiene valor predeterminado (es decir, pública y parameterl ess) constructor, en cuyo caso la declaración new T() dentro del método no sería válida.

  1. Con solamente Bar como una restricción, T puede ser Bar o cualquier derivado de Bar, con o sin un constructor predeterminado.
  2. Con solo new() como una restricción, T puede ser de cualquier tipo con un constructor predeterminado.
  3. Con Bar y new() como restricciones, T debe ser o una subclase de Bar y también debe tener un constructor predeterminado.
+0

@Ruben: ¡Exactamente !. Los tipos derivados de 'Bar' no necesariamente tienen un constructor predeterminado, incluso si' Bar' sí mismo, de ahí la necesidad de la restricción 'new()' también. – LukeH

+0

+1: Niza enumeración de las posibilidades; Sin información floja y potencialmente engañosa (y otros comentarios importantes sobre mi respuesta) –

1

Aunque Bar puede ser concreto, la clase derivada T podido por sí misma ser abstracta o la falta de un constructor por defecto.

+0

Diría que * puede ser * en lugar de * es *. A la especificación de la plantilla no le importa de ninguna manera hasta que digas 'new()' pero no te permitirá 'new()' en el cuerpo –

+0

En mi respuesta s/template/generic method /: D También s/the derived/a derived /. s/constructor por defecto/constructor parmaeterless público/ –

2

Porque las subclases de Bar pueden no tener un constructor no-arg.

where T : Bar 

indica Barra, o una subclase de Barra. Si solo quisiera una instancia de Bar, no usaría genéricos. Hay muchas instancias (Objeto y Cadena, por ejemplo) donde la superclase tiene un constructor sin arg y una subclase no.

+0

Como con las otras respuestas, hasta que digas: new(), T no tiene que tener un constructor [public parameterless] (y el cuerpo no puede usarlo) –

11

El hecho de que la clase Bar define un constructor sin parámetros, no quiere decir que todo lo que es un Bar lo hará - que puede haber una clase que hereda de Bar pero esconde el constructor sin parámetros. Tal clase cumpliría con la restricción Bar pero falla correctamente la restricción new().

(Tenga en cuenta que si haces Barsealed Para evitar esta posibilidad, puede (comprensiblemente) ya no utilizarlo como una limitación genérica) - edición de intentar esto produce error del compilador CS0701.

+0

Si bien es cierto, al compilador no le importa si incluso Bar tiene un constructor público sin parámetros [o le permite usarlo en el cuerpo] hasta que diga: ': new()' –

+0

+1. Simple, directo, correcto y responde el "Por qué" en la pregunta – AnthonyWJones

+0

¿Estás seguro de que el sellado excluye que coincida con una especificación de plantilla y genere realmente un error de compilación? (Me imagino que el compilador se da cuenta y no tiene mucho sentido si está sellado, ¿pero realmente se queja)? –

1

que probablemente podría tener utilizar el constructor de barras:

T _t = new Bar(); 

sin tener la restricción new(). Sin embargo, usaste el constructor T y el compilador no puede asumir que construyendo el tipo que se enlaza a T es posible hasta que agregas una nueva restricción().

+1

+1 Buen punto - Agregaría "y el compilador no puede y lo hace no suponga que construir el tipo que se une a T es posible hasta que agregue una restricción 'new()'. Si yo fuera el autor de la pregunta, me debatiría entre esto y el mío como la respuesta aceptada: P –

+0

Buena sugerencia, gracias – mbillard

0

Para aquellos que no está seguro, recuerde que puede utilizar el

where T : IDeviceCommand 

para requerir que T implementa alguna de las interfaces como un requisito mínimo de contratación. Podría verbalizar lo anterior como "Puede llamarme si el tipo suministrado 'T' como mínimo implementa la interfaz IDeviceCommand". Esto, por supuesto, le permite hacer una serie de suposiciones (correctas) de las instalaciones en las que 'T' proporciona su método para operar.

Cuestiones relacionadas