web-dev-qa-db-fra.com

Pourquoi le constructeur C # ne peut-il pas 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<T>
{
   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<int>?

Bien que vous puissiez contourner cela avec une classe d'usine,

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

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

155
theburningmonk

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

Non. Quand vous avez

new Foo(bar)

alors nous pourrions identifier tous les types appelés Foo dans la portée indépendamment de l'arité générique, puis faire une résolution de surcharge sur chacun en utilisant un algorithme d'inférence de type de méthode modifié. Il nous faudrait alors créer un algorithme de "bêtise" qui détermine lequel des deux constructeurs applicables dans deux types qui ont le même nom mais une arité générique différente est le meilleur constructeur. Afin de maintenir la compatibilité descendante, un ctor sur un type non générique doit toujours gagner.

Y a-t-il une raison pratique pour laquelle le constructeur ne peut pas prendre 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 pour implémenter une fonctionnalité. Non seulement la fonctionnalité doit être une victoire nette, elle doit être une grande victoire nette par rapport à toutes les autres fonctionnalités possibles dans lesquelles nous pourrions investir. Elle doit également être meilleure que de passer ce temps et des efforts sur la correction de bogues, le travail de performance et d'autres domaines possibles que nous pourrions mettre cet effort. Et idéalement, il doit bien s'intégrer dans le thème de la sortie.

De plus, comme vous le constatez correctement, vous pouvez profiter des avantages de cette fonctionnalité sans avoir réellement la fonctionnalité elle-même, en utilisant un modèle d'usine. L'existence de solutions de contournement simples rend moins probable la mise en œuvre d'une fonctionnalité.

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

MISE À JOUR mars 2015

La fonctionnalité proposée l'a fait assez près du haut de la liste pour que C # 6 soit spécifié et conçu, mais a ensuite été coupé.

126
Eric Lippert
public class MyType<T> 
{ 
   private readonly T field; 
   public MyType(T value) { field = value; } 
} 

ils le peuvent, il n'est pas nécessaire de dire à nouveau au constructeur "ce qu'est T", étant donné que vous l'avez déjà fait dans la classe decleration.

votre usine est également incorrecte, vous devez avoir public class MyTypeFactory<T> pas seulement public class MyTypeFactory - sauf si vous déclarez la fabrique dans la classe MyType

Modifier pour la mise à jour:

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

Disons que vous avez ce qui suit

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);

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

Quand vous vouliez vraiment le type base

D'où le

var myType = new MyType<Base>(c);
18
PostMan

La principale raison pour laquelle l'inférence de type générique ne peut pas fonctionner sur les 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 <T>". N'oubliez pas qu'il est légal d'avoir les deux:

public class MyType<T> {
}

et

public class MyType {
}

Les deux seraient légaux. Comment pouvez-vous lever l'ambiguïté de votre syntaxe si vous déclariez en fait les deux, et les deux déclaraient un constructeur en conflit.

12
Kirk Woll

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 le int dans votre exemple se rapporterait à la classe ou au constructeur.

var obj = new MyType<int>(42);

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

1
Albin Sunnanbo

Bien que cela ait été répondu plusieurs fois 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 qu'il ne prend en charge ni l'ajout de paramètres génériques aux constructeurs ni type l'inférence de type générique. Vouloir déduire un argument de type générique du type lui-même revient essentiellement à exiger que Foo.Bar(0) infère à Foo<int>.Bar(0).

0
IllidanS4