2010-04-22 7 views
33

Je joue avec l'API de réflexion C#. Je peux facilement charger Type des informations de classes, méthodes etc. dans un assemblage, cependant, maintenant je me demande comment puis-je charger et lire le code dans une méthode?Puis-je utiliser la réflexion pour inspecter le code d'une méthode?

+0

Qu'est-ce que est le scénario qui rend cela utile? Il casse l'un des locataires fondamentaux de OO qui est l'encapsulation. Mais de plus le code comme IL n'est pas vraiment le même. – DevelopingChris

+8

@DevelopingChris: Si vous écrivez un outil de débogage ou d'analyse de code, il peut être utile de charger un assemblage et d'analyser le corps d'une méthode. C'est, en fait, ce que font les outils comme FxCop. – LBushkin

+0

Le public cible de .NET est constitué de sociétés américaines (et secondairement peut-être de petites entreprises). Si vous pouviez contourner l'obfuscation .NET, le logiciel (cher à produire) pourrait facilement voler dans les doigts d'un concurrent. – micahhoover

Répondre

31

Réponse de base:

Vous ne pouvez pas avec l'API de réflexion (System.Reflection). La raison en est que l'API de réflexion est conçue pour fonctionner sur les métadonnées (type de classes, nom et signature des méthodes, ...) mais pas sur le niveau de données (qui serait le flux IL lui-même).

Réponse étendue:

Vous pouvez émettre (mais pas lire) IL avec System.Reflection.Emit (par exemple ILGenerator classe).

Grâce à MethodInfo.GetMethodBody(), vous pouvez obtenir le flux IL binaire pour la mise en œuvre d'une méthode. Mais c'est généralement complètement inutile en soi.

Il existe des bibliothèques externes (telles que Cecil) que vous pouvez utiliser pour lire/modifier/ajouter/supprimer du code dans une méthode.

+1

Vous ne pouvez pas vous référer à la méthode via un délégué, puis créer un ExpressionTree à partir du délégué et inspecter l'arborescence? –

+1

@Matt Greer: Non. Vous ne pouvez pas "désosser" le corps d'un délégué dans un arbre d'expression. – LBushkin

+0

@Matt: Cela ne va pas vous donner le code * à l'intérieur * de la méthode, vous obtiendrez juste une 'MethodCallExpression' qui vous donne accès au même' MethodInfo' que vous auriez pu obtenir plus directement avec l'API de réflexion. – Aaronaught

1

Non
Ceci est une fonctionnalité prévue pour la prochaine version de C#. Vous pouvez utiliser le CodeDom pour obtenir plus d'informations que la réflexion, mais vous ne pouvez pas encore interroger l'arbre d'analyse. Bien qu'il y ait toujours du mono, en mono, le compilateur est un service, et vous pouvez obtenir les arborescences d'analyse à l'exécution.

La meilleure question est pourquoi vous voulez?

1

Oui, il doit y avoir un moyen d'y parvenir: L'outil .NET Reflector le fait également. Je ne peux pas vous dire comment cela se fait, cependant.

+1

Pourquoi ne pas refléter le réflecteur;) – ntziolis

+9

Le réflecteur ne fonctionne pas réflexion au moins pas dans le sens de la réflexion .NET cadre. Il analyse réellement le fichier PE et dissocie le code IL de la section .TEXT. Ensuite, un modèle très intelligent et cool correspondant à la carte/décompiler l'IL retour à une langue cible. –

2

Si vous n'avez pas besoin de faire cela en temps réel, jetez un oeil à Reflector. Vous pouvez désassembler tout assembly .NET (y compris les DLL core MS) et voir le code dans la langue de votre choix. Cela peut être très éducatif.

Mise à jour Est-ce que quelqu'un a essayé d'utiliser Reflector on Reflector pour comprendre comment cela est fait?

+1

Notez que cela ne désoptimise pas le code. Donc, s'il y avait une optimisation du compilateur faite à l'IL, il n'est pas retourné à sa source de construction d'origine, mais à une version optimisée légèrement moins humaine.C'est un bon moyen de voir ce que vous pourriez faire le plus efficacement. – DevelopingChris

+0

Vous ne pouvez pas utiliser Reflector on Reflector. Essayez-le et voyez, vous aurez une bonne surprise. – Aaronaught

+1

Réflecteur est crypté de sorte qu'il ne peut pas réfléchir sur lui-même, je pense qu'ils ont utilisé DotFuscator pour le faire. – DevelopingChris

16

Cela dépend de ce que vous voulez dire par lire le code. Il y a 4 formes du code.

1- Le code source par ex. l'original C# ou VB.NET - Non, vous ne pouvez pas obtenir cela avec la réflexion
2- Le code IL symbolique - Non, vous ne pouvez pas obtenir cela avec la réflexion
3- Le code assembleur JITed - Non, vous ne pouvez pas obtenir cela avec la réflexion

4- Les octets IL, les octets réels dans lesquels IL est compilé, ce pouvez obtenir.

Jetez un oeil à MethodBase.GetMethodBody() par exemple, vous pouvez obtenir les octets IL, les variables locales, les cadres d'exception, etc. http://msdn.microsoft.com/en-us/library/system.reflection.methodbase.getmethodbody.aspx

+0

'GetMethodBody()' est le plus proche, je pense. – LBushkin

9

Vous sorte de pouvez. La fonction pertinente est MethodBase.GetMethodBody.

Ce n'est pas exactement l'API la plus utile. Vous pouvez obtenir des informations de base sur ce qu'il y a dans la méthode, et vous pouvez obtenir l'IL en tant que tableau d'octets. C'est à peu près ça.

Il y a un peu mieux API dans la bibliothèque Mono.Cecil, qui expose une MethodDefinition classe avec sa propre implémentation MethodBody qui contient Instructions réelle, de sorte que vous ne devez pas interpréter le code d'octet brut. Pourtant, si vous cherchez à obtenir le code C# à la réflecteur, vous allez être très déçu. De plus, Cecil n'est pas très bien documenté.

Si vous voulez toujours essayer, alors bonne chance.

Questions connexes