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
Свик еще раз спасибо! Я собираюсь поэкспериментировать с кодом в вашем ответе здесь и посмотреть, смогу ли я ответить на свой вопрос о добавлении методов, которые принимают параметры. Если у меня все еще возникают трудности с методом ResolveOverloads, я просто опубликую новый вопрос. - person Beaker; 04.05.2013
comment
Один совет: вы всегда должны использовать LookupSymbols для чего-то подобного, так как вам также нужно убедиться, что метод доступен на сайте вызова. LookupSymbols делает это, а GetMembers — нет. - person Jason Malinowski; 05.05.2013