EDIT : J'ai maintenant a publié un blog à ce sujet de manière plus détaillée.
Ma pensée initiale (et je pense maintenant qu'elle est incorrecte) : les contraintes génériques ne sont pas prises en compte pendant les phases de résolution des surcharges et d'inférence de type - elles ne sont utilisées que pour valider le résultat de la résolution des surcharges.
EDIT : Ok, après un lot d'aller et venir sur ce sujet, je pense que j'y suis. En gros, ma première pensée était presque correct.
Les contraintes de type générique n'agissent que pour supprimer les méthodes d'un ensemble de candidats dans un système de gestion de l'information. muy un ensemble limité de circonstances... en particulier, seulement lorsque le type d'un paramètre lui-même est générique ; pas seulement un paramètre de type, mais un type générique qui utilise un paramètre de type générique. À ce stade, ce sont les contraintes sur les paramètres de type du type générique qui sont validées, et non les contraintes sur les paramètres de type de la méthode générique que vous appelez.
Par exemple :
// Constraint won't be considered when building the candidate set
void Foo<T>(T value) where T : struct
// The constraint *we express* won't be considered when building the candidate
// set, but then constraint on Nullable<T> will
void Foo<T>(Nullable<T> value) where T : struct
Donc si vous essayez d'appeler Foo<object>(null)
la méthode ci-dessus ne le fera pas faire partie de l'ensemble des candidats, car Nullable<object> value
ne satisfait pas aux contraintes de Nullable<T>
. S'il existe d'autres méthodes applicables, l'appel peut encore aboutir.
Maintenant, dans le cas ci-dessus, les contraintes sont exactement les mêmes... mais elles ne doivent pas l'être. Par exemple, considérons :
class Factory<TItem> where TItem : new()
void Foo<T>(Factory<T> factory) where T : struct
Si vous essayez d'appeler Foo<object>(null)
la méthode fera toujours partie de l'ensemble des candidats, car lorsque l TItem
es object
la contrainte exprimée dans Factory<TItem>
tient toujours, et c'est ce qui est vérifié lors de la construction de l'ensemble des candidats. Si cette méthode s'avère être la meilleure, elle échouera à la validation ultérieure, à proximité de l'option fin de 7.6.5.1 :
Si la meilleure méthode est une méthode générique, les arguments de type (fournis ou inférés) sont vérifiés par rapport aux contraintes (§4.4.4) déclarées sur la méthode générique. Si un argument de type ne satisfait pas la ou les contraintes correspondantes sur le paramètre de type, une erreur de liaison se produit.
Eric article de blog contient plus de détails à ce sujet.
0 votes
Belle trouvaille ! Mais quelle est votre question ? Une solution de contournement ?
2 votes
Bonne question. Je pensais avoir une réponse simple, mais il s'avère que ce n'est pas le cas. J'espère que cela ne vous dérange pas que ma "réponse" soit davantage une exploration de ce qui se passe qu'une réponse en soi.
0 votes
Merci pour vos commentaires. Eamon - désolé, ma question n'est pas très claire - il s'agit en fait de savoir pourquoi le compilateur ne peut pas déterminer la meilleure méthode à utiliser. Après avoir lu les commentaires et les questions, ainsi que le lien fourni par LukeH, c'est parce que le compilateur ne prend pas en compte les contraintes de type pour déterminer la meilleure méthode à utiliser.
0 votes
J'ai modifié ma réponse. Je pense que je comprends maintenant ce qui se passe, mais c'est assez difficile à expliquer...
0 votes
Comme les contraintes (et les types de retour) ne font pas partie de la signature de la méthode, le simple fait de déclarer les deux méthodes vous donnera une erreur de compilation (pour avoir le même nom pour la même définition).