7
votes

Qui décide effectivement quel est le type générique?

J'ai cette fonction xxx pré>

Je crée 2 personnes d'instances de classe: p> xxx pré>

J'appelle la fonction avec: P>

 MyClass.MyFunc(p, p2, 5);


1 commentaires

Il n'y a pas de «décision». Une correspondance est trouvée ou une erreur se produit. Essayez simplement myfunc (P1, "", 5) ou myfunc ("", p2, 5) .


6 Réponses :


7
votes

La possibilité d'omettre les types d'appel dans l'appel xxx

est un bonbon de syntaxe (sauf si vous utilisez des types anonymes), et il compile exactement identique à Xxx

Le compilateur déduit les valeurs de t1 et t2 en fonction des types des paramètres A , B et C . Si p1 et p2 est de types incompatibles (voir Réponse de Svick , le compilateur ne sera pas en mesure de déduire t1 et cela entraînera une erreur de compilation.


9 commentaires

Néanmoins, le compilateur a besoin d'une ancrage pour voir s'il devrait vérifier que Apple ou Orange


Je pense que le compilateur ne se soucie pas de ce que les types sont, il vérifie simplement si les premier et second paramètres sont du même type.


@Royinamir, vous parlez de personnes et vous parlez de pommes et d'oranges ... Désolé, j'ai du mal à vous suivre :)


@Ilakogan Lorsque le compilateur se trouve T1, il devrait vérifier si T2 == T1 ou lorsqu'il voit des chèques T2 - E si T2 == T1.


T1 == T2 est la même chose que T2 == T1, nous parlons de type de la perspective du compilateur ici, pas d'une instance n'est égale à la vérification.


@ROYINAMIR Il ne vérifie pas si p1 == p2 . Il vérifie si typeof (p1) == typeof (p2) .


Ce n'est pas seulement Syntaxe Sugar si vous utilisez des types anonymes. Et il peut toujours compiler même si p1 et p2 sont différents types.


Merci, @svick, j'ai édité la réponse à mentionner des types anonymes. Pouvez-vous donner un exemple où cela compilera avec deux types différents?


@Ilakogan, voir Ma réponse pour des exemples de cela.



2
votes

Il n'y a pas de priorité, les deux (A et B) doivent être identiques, c'est-à-dire par conception, T1 est résolu à la compilation. Si vous changez sur DYNAMIC , vous venez de reporter le type de type de type à l'exécution et il échouera ensuite à compilétime si les types ne sont pas identiques. Si vous voulez qu'ils soient différents, vous devez introduire T3.

EDIT:

La pièce intéressante: xxx

sorties: > xxx

mais ceci: xxx

lancera: xxx

Cependant Il semble que je vraiment besoin de trouver un bon livre ou une ressource sur les types dynamiques en C # 4.0 pour comprendre la magie se produire ici.


3 commentaires

Je ne sais pas si je comprends ce que tu veux dire, mais ... si A.getType () est égal à b.getType (), que c'est aussi vrai vice versa. Ils ont juste besoin d'être T1 (tant qu'il n'y a pas de dynamique évidemment, voir mon édition ci-dessus)


La magie de ce cas est extrêmement simple: un argument de type explicite dynamique est traité exactement comme si vous avez dit objet lorsque l'expression est analysée au moment de l'exécution. Si vous avez une question spécifique à propos de quelque chose que vous ne comprenez pas, c'est un site de questions-réponses; envisagez de poster une question.


Cela semble si évident maintenant, merci pour l'explication que vous avez postée.



0
votes

Au moment de la compilation Si les types sont explicites, le compilateur vérifiera les types de paramètres passés et voyez s'ils correspondent à des types dans les génériques (aucun conflit).

Quoi qu'il en soit, la vérification réelle est effectuée à "Runtime", le code générique compile comme générique de toute façon (contrairement aux modèles C ++). Et puis lorsque le compilateur JIT compile la ligne, il vérifiera et voyez s'il peut créer la méthode en fonction des modèles que vous avez donnés et les paramètres envoyés.


0 commentaires

1
votes

Qui décide effectivement du type T1? (P? P2?)

N'est-il pas évident? Les deux. Les types de p et p2 doivent être compatibles. Contrairement à quelles autres réponses disent, ils ne doivent pas nécessairement être les mêmes. La règle réelle est qu'il doit y avoir une conversion implicite de la part des types à l'autre.

donc, par exemple myfunc ("a", nouvel objet (), 5) est identique à myfunc ("A" objet ("A", 5) , car chaîne est implicitement convertible à objet . Comme un autre exemple, myfunc (42L, 42, 4) est identique à celui myfunc (42L, 42, 4) , car int < / code> est implicitement convertible à long .

En outre, il existe des cas où la possibilité de laisser le compilateur déduire les types n'est pas juste agréable, c'est nécessaire. Plus précisément, cela se produit lors de l'utilisation de types anonymes. Par exemple myFunc (nouveau {p = "p"}, nouveau {p = "p2"}, 5) ne peut pas être réécrit pour spécifier les types explicitement.


0 commentaires

1
votes

"Qui décide effectivement du type T1? (P2 P2?)"

Normalement, le compilateur C # décide cela. Si l'un des arguments de la méthode est dynamique, la décision est effectuée à l'exécution (par la bibliothèque Microsoft.cshaarp). Dans les deux cas, l'algorithme d'inférence de type décrit dans la spécification C # est appliqué: Les deux types de p et p2 sont ajoutés à t1 's ensemble de limites inférieures ( Les limites sont également possibles, mais uniquement lorsque des génériques de contravariation sont impliqués).

Ensuite, le compilateur choisit l'un des types dans l'ensemble des limites qui satisfont également à toutes les autres limites. Lorsqu'il n'y a qu'un seul lié, car p et p2 ont le même type, ce choix est trivial. Sinon (en supposant que seules les limites inférieures sont impliquées), cela signifie que le compilateur choisit un type de sorte que tous les autres types de candidats soient implicitement convertibles à ce type (quelle réponse de Svick décrit).

S'il n'y a pas de choix unique de ce type, l'inférence de type échoue - une autre surcharge est choisie si possible, sinon une erreur de compilateur se produit (lorsque la décision est effectuée à l'exécution (dynamique), une exception est lancée à la place).


2 commentaires

Vous vouliez dire Contravariant Generics.


@ Sciences LIPPERT: Oups, je mélange toujours les termes Covariance / Contravierce. En fait, je les ai regardés lors de la rédaction de cette question et j'ai toujours réussi à écrire le mauvais. Merci d'utiliser In / Out dans C #, c'est beaucoup plus facile à retenir.



13
votes

À un niveau de haut niveau, l'inférence de type de méthode fonctionne comme ceci.

Nous faisons d'abord une liste de tous les arguments em> - les expressions que vous fournissez - et leur paramètre formel correspondant Tapez em>. P>

Regardons un exemple plus intéressant que celui que vous donnez. Supposons que nous ayons p> xxx pré>

et le même appel. Nous faisons donc les correspondances: p> xxx pré>

puis nous faisons une liste de ce que "limites" sont sur chaque paramètre de type et qu'ils sont "fixes". Nous avons deux paramètres de type et nous commençons avec aucune limite supérieure, inférieure ou exacte. P> xxx pré>

(rappelez notre récente discussion dans une autre question sur les tailles relatives des types de types étant basés sur si un type était plus ou moins restrictif; un type plus restrictif est plus petit em> que celui qui est moins restrictif. La girafe est plus petite que l'animal, car plus de choses sont des animaux que les girafes. Le "supérieur "et les ensembles liés" inférieurs "sont exactement que: la solution au problème de l'inférence de type pour un paramètre de type donné doit être plus grande ou identique à em> chaque borne inférieure et plus petite ou identique à toutes les limites supérieures, et identiques à em> toutes les limites exactes.) p>

Nous examinons ensuite chaque argument et son type correspondant. (Si les arguments sont lambdas, nous devrions peut-être comprendre l'ordre em> dans lequel nous examinons des arguments, mais vous n'avez pas de lambdas ici, alors ignorons ce détail.) Pour chaque argument que nous faisons Une inférence em> au type de paramètre formel et ajoutez les faits que nous déduisons de cette inférence à l'ensemble lié. Ainsi, après avoir examiné le premier argument, nous déduisons les limites: p> xxx pré>

après le deuxième argument que nous déduirons les limites p> xxx pré> > Après le troisième argument, nous déduisons les limites: P>

T1: (fixed) Person
T2: (fixed) int


6 commentaires

J'ai l'impression que le compilateur m'a donné une réponse. Merci beaucoup . (encore)


@Royinamir: De rien. J'ai ajouté des liens avec des articles et des vidéos utiles si vous souhaitez plus d'informations sur ce sujet.


Donc, C # 4 ajouté les limites supérieures? Pourquoi donc? Dans quelles situations sont-elles utiles?


@svick: Les limites supérieures ne sont que même possibles lorsque l'inférence de type générique doit être faite impliquant une conversion Contravariant . Étant donné que C # 3 n'a eu que des conversions de covariant ou non variantes, il n'y avait aucun moyen de ne jamais entrer dans une situation où il y avait même était une limite supérieure, nous n'avons même pas la peine de les mentionner dans l'algorithme. Lorsque nous avons ajouté des conversions Covariant et Contravariant sur des interfaces génériques et des délégués au C # 4, nous avons ajouté des déductions de la limite supérieure à l'algorithme d'inférence de type.


Pouvez-vous s'il vous plaît dire où je peux télécharger l'algorithme d'inférence vidéo complète de la vôtre que vous avez liée à votre réponse: blogs.msdn.com/b/ericlippert/archive/2006/11/17/... et c'est un lien direct dans Ce blog post WM.MICROSOFT.COM/MS/MSDN/VISUALCSHARP/ERIC_LIPPERT_2006_11 / ... . J'ai une connexion lente c'est pourquoi demander :)


@ M3taspl0it: aucune idée, désolé.