Pourquoi ne pas C# soutien implicite des types génériques sur les constructeurs de classe?

StackOverflow https://stackoverflow.com/questions/45604

  •  09-06-2019
  •  | 
  •  

Question

C# n'a pas besoin de spécifier un paramètre de type générique si le compilateur peut déduire, par exemple:

List<int> myInts = new List<int> {0,1,1,
    2,3,5,8,13,21,34,55,89,144,233,377,
    610,987,1597,2584,4181,6765};

//this statement is clunky
List<string> myStrings = myInts.
    Select<int,string>( i => i.ToString() ).
    ToList<string>();

//the type is inferred from the lambda expression
//the compiler knows that it's taking an int and 
//returning a string
List<string> myStrings = myInts.
    Select( i => i.ToString() ).
    ToList();

Cela est nécessaire pour des types anonymes où vous ne savez pas ce que le paramètre type serait (dans intellisense, il apparaît comme 'a) car il est ajouté par le compilateur.

Au niveau de la classe de type paramètres de ne pas vous laisser faire cela:

//sample generic class
public class GenericDemo<T> 
{
    public GenericDemo ( T value ) 
    {
        GenericTypedProperty = value;
    }

    public T GenericTypedProperty {get; set;}
}

//why can't I do:
int anIntValue = 4181;
var item = new GenericDemo( anIntValue ); //type inference fails

//however I can create a wrapper like this:
public static GenericDemo<T> Create<T> ( T value )
{
    return new GenericDemo<T> ( value );
}

//then this works - type inference on the method compiles
var item = Create( anIntValue );

Pourquoi ne pas en C# de soutenir ce niveau de la classe de l'inférence de type générique?

Était-ce utile?

La solution

En fait, votre question n'est pas mauvais.J'ai joué avec un générique langage de programmation pour les dernières années, et bien que je n'ai jamais vu autour de réellement développer (et probablement ne le sera jamais), j'ai pensé à beaucoup de choses sur l'inférence de type générique et une de mes priorités a toujours été de permettre la construction de classes sans avoir à spécifier le type générique.

C# n'a tout simplement pas l'ensemble des règles pour rendre cela possible.Je pense que les développeurs n'ont jamais vu le neccesity pour en tenir compte.En fait, le code suivant devrait être très proche de votre proposition et de résoudre le problème.Tous les C# est un ajout en charge de la syntaxe.

class Foo<T> {
    public Foo(T x) { … }
}

// Notice: non-generic class overload. Possible in C#!
class Foo {
    public static Foo<T> ctor<T>(T x) { return new Foo<T>(x); }
}

var x = Foo.ctor(42);

Étant donné que ce code fonctionne réellement, nous avons montré que le problème n'est pas de la sémantique, mais simplement d'un manque de soutien.Je suppose que je dois reprendre mon précédent commentaire.;-)

Autres conseils

Pourquoi ne pas en C# de soutenir ce niveau de la classe de l'inférence de type générique?

Parce qu'ils sont généralement ambiguë.En revanche, l'inférence de type est trivial pour les appels de fonction (si tous les types apparaissent dans les arguments).Mais dans le cas du constructeur appelle (glorifié fonctions, pour l'amour de la discussion), le compilateur doit résoudre plusieurs niveaux en même temps.Un niveau est le niveau de la classe et de l'autre les arguments du constructeur de niveau.Je crois que la résolution de ce est algorithmiquement non-trivial.Intuitivement, je dirais que c'est même NP-complet.

Pour illustrer un cas extrême où la résolution est impossible, d'imaginer que la classe suivante et dites-moi ce que le compilateur doit faire:

class Foo<T> {
    public Foo<U>(U x) { }
}

var x = new Foo(1);

Merci Konrad, c'est une bonne réponse (+1), mais juste à la renforcer.

Imaginons que le C# est un constructeur explicite de la fonction:

//your example
var x = new Foo( 1 );

//becomes
var x = Foo.ctor( 1 );

//your problem is valid because this would be
var x = Foo<T>.ctor<int>( 1 );
//and T can't be inferred

Vous avez tout à fait raison que le premier constructeur ne peut pas être déduit.

Revenons maintenant à la classe

class Foo<T> 
{
    //<T> can't mean anything else in this context
    public Foo(T x) { }
}

//this would now throw an exception unless the
//typeparam matches the parameter
var x = Foo<int>.ctor( 1 );

//so why wouldn't this work?
var x = Foo.ctor( 1 );

Bien sûr, si j'ajoute votre constructeur de nouveau (avec son autre type), nous avons l'ambiguïté d'un appel - exactement comme si un normal surcharge de la méthode ne pouvait pas être résolu.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top