Pourquoi le constructeur C # ne peut-il pas en déduire le type?

Pourquoi l’inférence de type n’est-elle pas prise en charge pour les constructeurs comme pour les méthodes génériques?

public class MyType { private readonly T field; public MyType(T value) { field = value; } } var obj = new MyType(42); // why can't type inference work out that I want a MyType? 

Bien que vous puissiez contourner ce problème avec une classe d’usine,

 public class MyTypeFactory { public static MyType Create(T value) { return new MyType(value); } } var myObj = MyTypeFactory.Create(42); 

Y a-t-il une raison pratique ou philosophique pour laquelle le constructeur ne supporte pas l’inférence de type?

Y a-t-il une raison philosophique pour laquelle le constructeur ne supporte pas l’inférence de type?

Non quand vous avez

 new Foo(bar) 

alors nous pourrions identifier tous les types appelés Foo dans la scope indépendamment de leur caractère générique, puis effectuer une résolution de surcharge sur chacun en utilisant un algorithme d’inférence de type méthode modifié. Nous devrons alors créer un algorithme de «trahison» qui détermine lequel des deux constructeurs applicables de deux types qui portent le même nom mais dont l’arité générique est différente est le meilleur constructeur. Afin de maintenir la compatibilité ascendante, un ctor sur un type non générique doit toujours gagner.

Y a-t-il une raison pratique pour laquelle le constructeur ne prend pas en charge l’inférence de type?

Oui. Même si les avantages de la fonctionnalité l’emportent sur ses coûts, qui sont considérables, cela ne suffit pas à implémenter une fonctionnalité. Non seulement la fonctionnalité doit être un gain net, mais elle doit être un gros gain net par rapport à toutes les autres fonctionnalités possibles dans lesquelles nous pourrions investir. travail, et d’autres domaines possibles que nous pourrions mettre cet effort. Et idéalement, il doit bien s’adapter à tout ce que le “thème” est de la version.

De plus, comme vous le remarquez correctement, vous pouvez tirer parti de cette fonctionnalité sans avoir la fonctionnalité elle-même, en utilisant un motif d’usine. L’existence de solutions de contournement faciles rend moins probable la mise en œuvre d’une fonctionnalité.

Cette fonctionnalité est sur la liste des fonctionnalités possibles depuis longtemps maintenant. Il n’a jamais été assez haut sur la liste pour être réellement mis en œuvre.

MISE À JOUR Mars 2015

La caractéristique proposée le rapproche suffisamment du haut de la liste pour que le C # 6 soit spécifié et conçu, mais il est ensuite coupé.

 public class MyType { private readonly T field; public MyType(T value) { field = value; } } 

ils peuvent, il n’y a pas besoin de dire au constructeur ce que T est à nouveau, comme vous l’avez déjà fait dans la décomposition de classe.

votre fabrique est également incorrecte, vous devez avoir public class MyTypeFactory pas seulement public class MyTypeFactory – à moins que vous ne public class MyTypeFactory la fabrique dans la classe MyType

Modifier pour la mise à jour:

Eh bien, est-ce que 42 est un long, un court, un int ou autre chose?

Disons que vous avez le suivant

 class Base { public virtual void DoStuff() { Console.WriteLine("Base"); } } class Foo : Base { public override void DoStuff() { Console.WriteLine("Foo"); } } 

Alors tu as fait ça

 var c = new Foo(); var myType = new MyType(c); 

Souhaitez-vous que foo soit utilisé, ou base ? Nous devons dire au compilateur quoi utiliser à la place de T

Quand tu voulais vraiment sur type base

D’où le

 var myType = new MyType(c); 

La principale raison pour laquelle l’inférence de type générique ne peut pas fonctionner sur des constructeurs comme vous le souhaitez est que la classe “MyType” n’existe même pas lorsque tout ce que vous avez déclaré est “MyType “. Rappelez-vous qu’il est légal d’avoir les deux:

 public class MyType { } 

et

 public class MyType { } 

Les deux seraient légaux. Comment désambiguïser votre syntaxe si vous déclariez les deux, et que les deux déclaraient un constructeur en conflit.

Le constructeur doit avoir la même spécification générique que la classe elle-même. Sinon, il serait impossible de savoir si l’ int dans votre exemple serait lié à la classe ou au constructeur.

 var obj = new MyType(42); 

Serait-ce la classe MyType avec le constructeur MyType(int) ou la classe MyType avec le constructeur MyType(T) ?

Bien que cela ait été répondu à maintes resockets auparavant, je pense que je dois clarifier une chose: C # prend en charge l’ inférence de type générique sur les constructeurs. Le problème est que cela ne prend en charge ni l’ajout de parameters génériques aux constructeurs ni l’inférence de type générique. Vouloir déduire un argument de type générique du type luimême revient fondamentalement à exiger que Foo.Bar(0) Foo.Bar(0) .