7
votes

Lambda Expression pour la propriété de classe

Quelqu'un peut-il expliquer pourquoi le premier des deux exemples suivants est valide et l'autre n'est pas? Plus précisément, comment une relation est-elle créée entre t et tproperty dans le premier exemple?

void SomeMethod<T>( Expression<Func<T,Object>> expression ){ ... }


0 commentaires

4 Réponses :


0
votes

Le problème, aussi loin que je peux voir, est simplement que DateTime n'est pas une classe ... vous passez dans t comme DateTime (que ce soit implicite ou explicite).

Il est probablement aussi confus que dans le premier exemple, vous avez deux paramètres de type appelés t - un sur le type, et un sur la méthode. Ils sont en fait complètement séparés ... Pour être identiques, réécrivez le premier exemple que: xxx

ceci est maintenant le même t: classe < / p>


2 commentaires

Désolé mauvais exemple ... Évidemment DateTime est une structure. Fait des modifications à mon exemple pour espérer plus clairement le problème. En supposant que l'objet est en fait une classe avec des propriétés et non une structure.


Bien que cela soit vrai, et cela peut certainement être écrit de cette façon - je suis intéressé par l'endroit où la connexion est faite que TPROPERTY est réellement liée à T, permettant ainsi P => p.property dans l'expression sans jamais définir le type générique de TPRPERTY . Plus important encore, comment j'ai accompli la même chose avec une méthode qui n'est pas dans une classe générique. Est-ce que j'ai du sens? :)



1
votes

Tout d'abord, votre premier exemple est incorrect et ne compilera pas comme indiqué. Outre le manquant public sur la méthode, vous définissez t deux fois - une fois sur classe et une fois sur méthode. Ce n'est pas une erreur en soi (bien que vous obtenez un avertissement), mais lors de la compilation de l'appel de la méthode, vous obtiendrez la même erreur que vous décrivez obtenir par exemple # 2. Donc, je suppose que le code réel est comme celui-ci: XXX

En outre, vos exemples "ignorent" (c'est-à-dire enfreindre) le type réel de TPROPERTY dans votre Appelez à SOMEMETHOD . Votre deuxième exemple spécifie explicitement le type de t , oui, mais pas tproperty .

Il n'y a pas de relation implicite établie dans le premier exemple, non plus. Lorsque vous instaniez Someclass <> avec t = mydateclass , la signature de SOMEMETHOD pour cette instanciation devient effectivement: xxx

Donc, le type d'argument de la Lambda est connu à ce stade, vous n'avez donc pas à le spécifier. Le type de retour d'expression lambda est déduit en tant que type d'expression à droite de => , et ce sera le type inféré de TPROPERTY .

Dans le deuxième exemple, étant donné que t n'a pas été explicitement spécifié lors de l'instanciation de la classe, et car il n'ya aucun moyen de le déduire des arguments de la méthode, il doit être spécifié explicitement. Une fois que vous le spécifiez, TPROPERTY est désigné exactement de la même manière que pour l'exemple n ° 1.


5 commentaires

Je ne comprends pas ce que vous impliquez avec votre indicateur de commentaires. Dites-vous que aucun exemple ne devrait ne pas fonctionner car le type de TPROPERTY est inconnu dans les exemples? En ce qui concerne les erreurs de syntaxe, oui, coupable comme chargé - je n'ai pas essayé de compiler ces exemples avant de poster.


"Inférer" signifie "Trouver automatiquement le type". Dans ce cas, il va comme suit: Type de t est connu -> T1 dans FUNC est connu -> Type de dt est connu -> Le type de retour de Lambda est déduit en tant que type d'expression dt.year (une fois que nous connaissons le type de dt , nous avons évidemment Connaître le type de dt.year -> treesult dans Func est connu -> TPROPERTY est connu.


La confusion n'est pas avec une compréhension de ce que signifie un inducteur, mais comment définir MyDaTeclass au niveau de la classe par rapport au niveau de la méthode fait une différence. c'est à dire; Soméclass , Somemethod ... Dans ces deux cas T1 est connu, alors pourquoi le type de TPROPERTY a-t-il été inféré il premier exemple mais pas la seconde?


Oh, je vois maintenant. Si votre exemple n ° 2 est pris exactement comme indiqué, l'erreur du compilateur est simplement parce que vous ne spécifiez pas TPROPERTY . Ce n'est pas parce que cela ne peut pas être déduit, mais parce que, contrairement à C ++, C # ne vous permet pas de spécifier explicitement certains paramètres de type dans un appel de méthode, mais omettez les autres. Vous vous omettez tous tout d'entre eux (et laissez-les déduire) ou vous spécifiez tout.


Exactement. :) Désolé si je n'étais pas clair. J'ai essayé de baisser l'exemple, mais j'ai peut-être obscurcier le problème en ajoutant des erreurs de compilateur avec le code Adhoc. Excuses.



1
votes

Plutôt que de taper les spécificités, jetez un coup d'œil à ce message par Eric Lippert . Je pense que cela répondra à ce que vous essayez de demander.

Je me rends compte que c'est long et conçu, mais je pense que c'est le meilleur coup pour le Buck pour vous répondre.


0 commentaires

7
votes

Vous permettrez au compilateur d'inférer les paramètres de type. Cela fonctionne bien pour le cas 1: xxx pré>

parce que vous déclarez d'abord une instance: p> xxx pré>

qui indique au compilateur que t est MyDateclass code>. Ensuite, lorsque vous appelez la méthode: p>

sc.SomeMethod((MyDateClass dt) => dt.Year );


6 commentaires

Donc, efficacement le compilateur effectue la magie dans le premier exemple? Faire une hypothèse que TPROPERTY devrait être un int car .year est un int? Cela répondrait à ma question, je ne peux pas dire que c'est satisfaisant cependant. :)


... Je pense que la lumière est juste descendue. La DIFF entre la classe et la méthode est que la classe implique qu'une instance de T existe dans son contexte, tandis que la méthode n'est pas? D'où les hypothèses du compilateur?


Je ne sais pas pourquoi vous n'êtes pas satisfait, mais l'inférence de type statique n'est pas une magie et a des règles explicites et est une nouvelle fonctionnalité en C #.


@Ikariii - Je ne suis pas sûr de ce que vous impliquez. Ce n'est pas contextuel, T est connu dans le premier exemple car vous deviez le préciser à la création de classe. Vous vous attendez à ce que cela soit déduit dans la seconde.


Droite ... Mais quelle est la différence entre spécifier T au niveau de la classe et spécifier au niveau de la méthode? Soméclass vs Somemethod ... dans les deux cas t est connu n'est-ce pas?


Merci Mark, je pense que vous avez compris le problème exactement et avons pu articuler une réponse pour amener mon cerveau à partir d'un époque à queue! :)