Roslyn CTP - Модификация на случаен код

Експериментирах с Roslyn API в сценарий тип генетично програмиране. Изглежда като чудесен начин за извършване на този тип програмиране, но действителното прилагане на прости сценарии не изглежда много лесно, което означава, че вероятно нямам добро разбиране как да използвам правилно този API. Ето една проста програма, която се опитвам да модифицирам в моите експерименти:

string treeText = @"using System;
                                using System.Collections.Generic;

                                namespace TestProgram
                                {
                                    class Program
                                    {
                                        static void Main(string[] args)
                                        {
                                            var myVar = 3;
                                            string myString = ""Hello World"";
                                            List<string> stringList = new List<string>();
                                            Console.WriteLine(myString + myVar);
                                            Console.ReadLine();
                                        }
                                    }
                                }";

SyntaxTree tree = SyntaxTree.ParseText(treeText);

var compilation = Compilation.Create("test.exe",
        syntaxTrees: new[] { tree },
        references: new[]
            {
                new MetadataFileReference(typeof(object).Assembly.Location),
                new MetadataFileReference(typeof(Enumerable).Assembly.Location),
            });

        SemanticModel model = compilation.GetSemanticModel(tree);

Само като прост пример, нека кажем, че някак "случайно" реших, че искам да вмъкна ново извикване на метод, използвайки екземпляра myString. Какъв би бил ефективен начин да разбера какви методи мога да извикам от този екземпляр? Тогава какъв би бил най-добрият начин да създам необходимия MethodInvocationSyntax (след като избера конкретен метод за използване) от информацията за символа? Намерих метод, наречен ResolveOverloads, в класа SemanticModel, който се появява там, където трябва да отида, но имам известни затруднения да измисля ефективен път към параметрите, които този метод изисква. Това ли е правилният път, по който трябва да се върви?


person Beaker    schedule 04.05.2013    source източник


Отговори (1)


Първо вземете VariableDeclaratorSyntax за вашата променлива, например:

var variable = tree.GetRoot().DescendantNodes()
                   .OfType<VariableDeclaratorSyntax>()
                   .Single(v => v.Identifier.ValueText == "myString");

След това вземете LocalSymbol за тази променлива от SemanticModel:

var variableSymbol = (LocalSymbol)model.GetDeclaredSymbol(variable);

След това можете да получите списък с методи, които можете да извикате на тази променлива въз основа на нейния тип. Можете или просто да получите всички членове от типа, които са методи на екземпляр:

var methods =
    variableSymbol.Type.GetMembers()
                  .OfType<MethodSymbol>()
                  .Where(m => !m.IsStatic && m.MethodKind == MethodKind.Ordinary);

Или, ако искате да включите методи за разширение, можете да използвате LookupSymbols():

var methods = model.LookupSymbols(
    variable.GetLocation().SourceSpan.Start, variableSymbol.Type,
    options: LookupOptions.IncludeExtensionMethods)
                   .Where(m => !m.IsStatic);

След това можете да изберете един от наличните методи въз основа на вашата логика и да създадете InvocationExpressionSyntax (следният код предполага, че е метод без параметри):

var invocationExpression =
    Syntax.InvocationExpression(
        Syntax.MemberAccessExpression(
            SyntaxKind.MemberAccessExpression,
            Syntax.IdentifierName(variableSymbol.Name),
            (SimpleNameSyntax)Syntax.ParseName(selectedMethod.Name)));

След това ще трябва да разберете къде във вашия метод да добавите израза и какво да правите с неговия резултат (ако има нещо).

person svick    schedule 04.05.2013
comment
Благодаря отново swick! Ще експериментирам с кода във вашия отговор тук и ще видя дали мога да отговоря на собствения си въпрос относно добавянето на методи, които приемат параметри. Ако все още имам затруднения с метода ResolveOverloads, тогава просто ще публикувам нов въпрос. - person Beaker; 04.05.2013
comment
Един съвет: винаги трябва да използвате LookupSymbols за нещо подобно, тъй като също трябва да се уверите, че методът е достъпен на сайта за повикване. LookupSymbols прави това, докато GetMembers не. - person Jason Malinowski; 05.05.2013