2010-04-30 20 views
5

El siguiente código no se puede compilar, produciendo un error "Widget debe ser un tipo no abstracto con un constructor sin parámetros público". Creo que el compilador tiene toda la información que necesita. ¿Es esto un error? ¿Un descuido? ¿O hay algún escenario donde esto no sería válido?¿Por qué la restricción genérica new() no satisface una clase con parámetros opcionales en el constructor?

public class Factory<T> where T : new() 
{ 
    public T Build() 
    { 
     return new T(); 
    } 
} 

public class Widget 
{ 
    public Widget(string name = "foo") 
    { 
     Name = name; 
    } 

    public string Name { get; set; } 
} 

public class Program 
{ 
    public static void Main() 
    { 
     var widget = new Widget(); // this is valid 
     var factory = new Factory<Widget>(); // compiler error 
    } 
} 
+0

Paginación Eric Lippert ... Creo que esto se debe a los parámetros opcionales que son una característica del compilador, pero las restricciones genéricas son CLR. Entonces, los parámetros opcionales son sustituidos por el compilador, y el JIT simplemente ve los parámetros (requied). – Richard

+0

@Richard: Ese es básicamente el problema aquí. Los parámetros opcionales tienen algunos efectos secundarios extraños para el control de versiones, también, por exactamente este motivo ... –

Respuesta

7

Aunque lógicamente debería funcionar, desafortunadamente no funciona. El CLR aún ve su constructor como un constructor basado en parámetros.

Recuerde que, aunque C# admite parámetros opcionales, esto se realiza en el nivel de compilación, en tiempo de compilación. El tipo subyacente solo contiene un constructor que toma un solo parámetro. En lo que se refiere al CLR, los "parámetros por defecto" se convierten en atributos, así:

public Widget(([Optional, DefaultParameterValue("foo")] string name) { // ... 

El CLR es un tiempo de ejecución en varios idiomas. Los genéricos están diseñados para trabajar en el nivel CLR, para todos los idiomas, por lo que las restricciones también deben ser verdaderas en los idiomas sin parámetros predeterminados. Los idiomas no son necesarios para comprender OptionalAttribute, ni DefaultParameterValueAttribute, por lo que no puede funcionar de manera uniforme para todos los idiomas, por lo tanto, no está permitido.


Editar:

En respuesta a tu comentario:

Lo que no entiendo es por qué el compilador de C# No se puede generar el código necesario para satisfacer el CLR

Teóricamente, el equipo compilador de C# podría hacer que el lenguaje genere dos constructores separados, en lugar de un constructor marcado con atributos. Esto, potencialmente, explotaría en muchos constructores, ya que los parámetros nombrados crean las capacidades para muchas, muchas combinaciones posibles de "constructores" (o llamadas a métodos para métodos), especialmente cuando hay múltiples argumentos disponibles. Personalmente, me alegro de que no lo hicieran, ya que causaría confusión debido a una sobreabundancia de métodos y constructores en los tipos generados, lo que haría que la API pública se viera muy diferente al código que la generó. Tome el siguiente constructor:

public Widget(
      int id = 0, 
      string name = "foo", 
      float width=1.0f, 
      float height=1.0f, 
      float depth=1.0f 
     ) { // ... 

¿Se le permite generar automáticamente todas las combinaciones posibles de aquí, el compilador necesita generar constructores de este constructor único, ya que hay N! posibles formas de llamar a esto ...

+0

@Joshua: El compilador de C# genera el código que pegué arriba. Así es como funciona: no está creando un constructor sin parámetros, sino uno opcional. Voy a editar para agregar detalles ... –

+0

Ok, gracias, eso explica por qué no funciona. Todavía me pregunto cuáles serían las implicaciones de generar el constructor sin parámetros. –

+0

@Joshua: Edité mi respuesta para explicar por qué esta es potencialmente una mala idea ... ¿Tiene más sentido ahora? Recuerde, no es solo opcional, también puede usar parámetros con nombre, entonces N parámetros significa N! posibles combinaciones que tendrían que generarse ... –

Cuestiones relacionadas