2010-04-30 3 views
5

Le code suivant ne peut pas être compilé, produisant une erreur "Widget doit être un type non-abstrait avec un constructeur public sans paramètre". Je pense que le compilateur a toutes les informations dont il a besoin. Est-ce un bug? Un oubli? Ou y a-t-il un scénario où ce ne serait pas valide?Pourquoi la contrainte générique new() n'est-elle pas satisfaite par une classe avec des paramètres optionnels dans le constructeur?

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

Pagination Eric Lippert .... Je pense que cela sera dû aux paramètres optionnels étant une fonctionnalité de compilateur, mais les contraintes génériques étant CLR. Les paramètres optionnels sont donc remplacés par le compilateur, et le JIT ne voit que les paramètres (requis). – Richard

+0

@Richard: C'est essentiellement le problème ici. Les paramètres optionnels ont des effets secondaires étranges pour la version, aussi, exactement pour cette raison ... –

Répondre

7

Bien que cela devrait logiquement fonctionner, ce n'est malheureusement pas le cas. Le CLR considère toujours votre constructeur comme un constructeur basé sur des paramètres. N'oubliez pas que, bien que C# prenne en charge les paramètres facultatifs, cela se fait au niveau du compilateur, au moment de la compilation. Le type sous-jacent contient toujours un constructeur prenant un seul paramètre. En ce qui concerne le CLR est concerné, les « paramètres par défaut » sont convertis en attributs, comme ceci:

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

Le CLR est un moteur d'exécution multi-langues. Les génériques sont conçus pour fonctionner au niveau CLR, pour toutes les langues, de sorte que les contraintes doivent également être vraies dans les langues sans paramètres par défaut. Les langues ne sont pas requises pour comprendre l'attribut OptionalAttribute, ni DefaultParameterValueAttribute, donc cela ne peut pas fonctionner uniformément pour toutes les langues, par conséquent, il n'est pas autorisé.


Edit:

En réponse à votre commentaire:

Ce que je ne comprends pas pourquoi le compilateur C# ne peut pas générer le code nécessaire pour satisfaire le CLR

Théoriquement, l'équipe du compilateur C# peut avoir le langage générer deux constructeurs distincts, au lieu d'un constructeur marqué avec des attributs. Cela pourrait potentiellement exploser dans de nombreux constructeurs, car les paramètres nommés créent les capacités pour beaucoup, beaucoup de combinaisons possibles de «constructeurs» (ou appels de méthodes pour les méthodes), en particulier lorsque plusieurs arguments sont disponibles. Personnellement, je suis content qu'ils ne l'aient pas fait, car cela causerait de la confusion en raison d'une surabondance de méthodes et de constructeurs dans les types générés, ce qui ferait que l'API publique serait très différente du code qui l'a généré. Prenez le constructeur suivant:

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

vous deviez générer automatiquement toutes les combinaisons possibles ici, le compilateur aurait besoin de générer constructeurs pour ce seul constructeur, car il y a N! façons possibles d'appeler cela ...

+0

@Joshua: Le compilateur C# génère le code que j'ai collé ci-dessus. C'est ainsi que cela fonctionne - ce n'est pas un constructeur sans paramètre, mais plutôt un constructeur facultatif. Je vais modifier pour ajouter des détails ... –

+0

Ok, merci, ça explique pourquoi ça ne marche pas. Je me demande encore quelles seraient les implications de la génération du constructeur sans paramètre. –

+0

@Joshua: J'ai édité ma réponse pour expliquer pourquoi c'est potentiellement une mauvaise idée ... Avoir plus de sens maintenant? Rappelez-vous, ce n'est pas seulement facultatif, vous pouvez également utiliser des paramètres nommés, donc N paramètres signifie N! combinaisons possibles qui auraient besoin d'être générées ... –

Questions connexes