Question

Est-il possible de convertir un MethodBody (ou une autre technique de réflexion) dans un arbre System.Linq.Expressions.Expression?

Était-ce utile?

La solution

Non, il n'y a pas.

Vous demandez essentiellement une version un peu plus simple de réflecteur .

Autres conseils

Oui, il est possible ... mais il n'a pas encore été fait, pour autant que je sache.

  

Si quelqu'un ne savoir d'une bibliothèque de-Compile méthodes pour les arbres d'expression, s'il vous plaît laissez-moi savoir, ou modifier l'énoncé ci-dessus.

La partie la plus difficile de ce que vous avez à faire est d'écrire un CIL de compilateur. C'est, vous avez besoin de traduire les instructions du CIL de façon juste de bas niveau (qui ciblent conceptuellement une machine à pile) dans beaucoup d'expressions de niveau supérieur.

Des outils tels que de Redgate réflecteur ou de Telerik JustDecompile faire exactement cela, mais au lieu de construire des arbres d'expression, ils afficher le code source; vous pourriez dire qu'ils vont un peu plus loin, puisque les arbres d'expression sont essentiellement encore la langue agnostique.

Quelques cas notables où cela obtiendrait particulièrement délicate:

  • Vous auriez à traiter les cas d'instructions CIL pour lesquelles aucun nœud d'arborescence de Expression prédéfini existe; disons, tail.call ou cpblk (je devine un peu ici). C'est, il faudrait créer des types de noeuds d'arbre d'expression personnalisés; les ayant compilé de nouveau dans une méthode exécutable lorsque vous .Compile() l'arbre d'expression peut être un problème, car le compilateur d'arbre d'expression tente d'éliminer les noeuds personnalisés dans les noeuds standard. Si cela est impossible, vous ne pouvez pas compilez l'arbre d'expression plus, vous ne pouvez l'inspecter.

  • tenteriez-vous de reconnaître certaines constructions de haut niveau, comme un bloc C # using, et essayer de construire un nœud d'arbre d'expression (personnalisé) pour cela? Rappelez-vous que les pauses C # de using à l'équivalent de try…finally { someObj.Dispose(); } lors de la compilation, de sorte que c'est-ce que vous pouvez voir au lieu de using si vous avez réfléchi sur instructions du CIL de corps de méthode et exception des clauses de manipulation .

    Ainsi, en général, attendez que vous devez être en mesure de « reconnaître » certains modèles de code et les résumer dans un concept de niveau supérieur.

Il est en effet possible, voir DelegateDecompiler:

https://github.com/hazzik/DelegateDecompiler

NOTE: Je suis pas affilié à ce projet

Modifier

Voici l'approche de base que le projet prend:

  1. Get MethodInfo pour la méthode que vous voulez convertir
  2. Utilisez methodInfo.GetMethodBody pour obtenir un objet MethodBody. Celui-ci contient, entre autres, le MSIL et les informations sur les arguments et les habitants
  3. Allez les instructions, examinez les opcodes et les expressions appropriées construire
  4. lier ensemble et retourner une expression optimisée

Voici un extrait de code du projet qui décompile un corps de méthode:

 public class MethodBodyDecompiler
    {
        readonly IList<Address> args;
        readonly VariableInfo[] locals;
        readonly MethodInfo method;

        public MethodBodyDecompiler(MethodInfo method)
        {
            this.method = method;
            var parameters = method.GetParameters();
            if (method.IsStatic)
                args = parameters
                    .Select(p => (Address) Expression.Parameter(p.ParameterType, p.Name))
                    .ToList();
            else
                args = new[] {(Address) Expression.Parameter(method.DeclaringType, "this")}
                    .Union(parameters.Select(p => (Address) Expression.Parameter(p.ParameterType, p.Name)))
                    .ToList();

            var body = method.GetMethodBody();
            var addresses = new VariableInfo[body.LocalVariables.Count];
            for (int i = 0; i < addresses.Length; i++)
            {
                addresses[i] = new VariableInfo(body.LocalVariables[i].LocalType);
            }
            locals = addresses.ToArray();
        }

        public LambdaExpression Decompile()
        {
            var instructions = method.GetInstructions();
            var ex = Processor.Process(locals, args, instructions.First(), method.ReturnType);
            return Expression.Lambda(new OptimizeExpressionVisitor().Visit(ex), args.Select(x => (ParameterExpression) x.Expression));
        }
    }
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top