9Fermer11
GoldenCrystalLe 14/08/2016 à 15:28
À tout hasard, ça serait pas du code de debug qui t'a généré ça ? ^^
Sinon, ce genre de trucs (les locales inutiles) c'est la classe

./8 > DynamicMethod peut sauter les vérifications de visibilité (c'est une fonctionnalité, c'est bien pratique), mais dans ton cas tu n'en a pas besoin, donc ce type de message ne devrait pas apparaître
Ton code généré ne doit générer aucun message à la moulinette peverify. Sinon, c'est que le code généré est mauvais, et ça peut expliquer des bugs étrange. (Ou pas)
Si tu sais retrouver le message d'erreur exact et le bout de code incriminé, je veux bien y jeter un œil ^^

Zeph > Typiquement, tout ce qui est du code haut niveau, où le compilateur fait un vrai boulot, est un territoire problématique. C'est là où on sort du domaine "Le CLR supporte les fonctionnalités abstraites de tous les langages" pour aller dans le domaine du "Le CLR ne permet pas de faire X nativement, mais on peut construire X avec les blocs fournis par le CLR". (Un peu comme on peut créer le CLR avec de l'assembleur x86… ça ne permet pas pour autant au CPU de comprendre ce qu'est un objet ^^)
La majorité des fonctionnalités de C#2.0* jusqu'à C#5.0** ne sont pas gérées par le CLR. Le CLR ne sait pas ce qu'est une expression lambda, n'a pas la moindre idée de ce qu'est une méthode d'extension, ignore complètement l’existence de méthodes asynchrones, etc. Tout ça, c'est problématique, parce que la promesse initiale qui disait "Le compilateur C# n'a pas besoin d'optimiser trop fort, car on peut faire ce travail au niveau du JIT et ça bénéficiera à tous les langages", ne vaut plus un clou dans ce contexte.
Si tu veux optimiser les méthodes async, les énumérateurs, les closures, ou que sais-je, tu dois d'abord décompiler le code, pour l'exprimer sous une forme avec laquelle tu pourrais travailler, puis ensuite le recompiler comme il faut. C'est un travail trop énorme pour un JIT, et en plus il n'y a pas de façon de faire standard. (Le compilateur implémente ses structures comme il veut.)

* C# 2.0 a apporté les closures avec la syntaxe "delegate {}" et les itérateurs. Par contre, la majorité de ses apports était lié à un gros ravalement de CLR et du JIT.
** C# 6.0 ne fait qu'ajouter du sucre syntaxique fort attendu ou exposer des fonctions natives du CLR, et tranche massivement avec ses 3 prédécesseurs. (Mais il y a Roslyn !)
Parlons des delegate

J'irai vérifier que c'est encore le cas à l'occasion, mais l'exemple qui me reste toujours en mémoire, c'est que dans l'utilisation des lambda, le compilateur C# va générer des closures inutiles, ou même des méthodes inutiles dans des cas où il pourrait faire sans. (une closure c'est deux allocations d'objet: une allocation pour l'instance, et une allocation pour le delegate)

Tout ça tient au fait qu'un delegate soit un pointeur de méthode, donc contienne une référence d'objet plus une référence de fonction et que le paramètre implicite d'instance this ne soit en réalité qu'un paramètre de méthode comme les autres.

Théoriquement, tu peux transformer une méthode statique de signature Func<A, B> en Func<B>, si A est de type référence.
Pratiquement, le compilateur t'autorise même à le faire toi-même via les méthodes d'extension: dans le contexte d'une création de delegate "reference.ExtensionMethod" va te créer un delegate dont la méthode est "ExtensionMethod" et l'objet "this" est "reference".

Théoriquement, si tu as besoin d'un Func<A, B> mais que tu n'as qu'une méthode d'instance "class A { B F() => default(B); }", tu peux avoir un delegate Func<A,B> directement, qui pointera "statiquement" sur la méthode "A.F".
En pratique, tu peux le faire, mais il n'existe aucun moyen au niveau du langage C# de faire ainsi. En C#, tu pourra faire une lambda "a => A.F()", mais ça va te générer une méthode (complètement inutile) de plus dans le code. Par contre, choppe la référence de méthode "A.F" et construis le delegate Func<A, B> à la main, et ça fonctionnera.

(Une variation de ça, c'est si un type d'objet A possède une propriété de type B, le getter est déjà une méthode qui peut être utilisée pour faire un delegate Func<A,B> ou Func<B> selon ce qui est désiré)

Je suis pas inspiré aujourd'hui donc j'ai pas de bon exemple de code sous la main, mais ce sont des trucs un peu couillons, car ça serait très facile pour le compilateur de détecter qu'il n'a pas besoin de créer une classe et/ou une méthode dans le cas de certains delegate. C'est d'autant plus bête que dans certains cas (je ne connais pas l'algorithme de décision) le compilateur s'embette à mettre en cache les instances de delegate. Combiné avec les optimisations qui ne sont pas faites aujourd'hui, tu pourrais passer de "n" allocations, voire "2n" allocations à une seule et unique allocation.