2013-05-04 31 views
3

我一直在基因編程類型的場景中試驗Roslyn API。這看起來是一種很好的方式來完成這種類型的編程,但是簡單場景的實際實現似乎並不簡單,這意味着我可能對如何正確使用此API沒有很好的理解。下面是一個簡單的程序,我想在我的實驗修改:Roslyn CTP - 隨機代碼修改

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(一旦我選擇了特定的方法來使用),最好的方法是什麼?我在SemanticModel類中找到了一個名爲ResolveOverloads的方法,該方法出現在我需要結束的地方,但我很難找出這種方法需要的參數的有效路徑。這是否是正確的道路?

回答

1

首先,獲得VariableDeclaratorSyntax爲您的變量,例如:

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

接下來,拿到LocalSymbolSemanticModel這個變量:

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))); 

你會TH需要找出你的方法中添加表達式的地方以及如何處理結果(如果有的話)。

+0

再次感謝svick!我將在這裏試驗你的答案中的代碼,看看我是否可以回答自己關於添加帶參數的方法的問題。如果我仍然遇到ResolveOverloads方法的困難,那麼我只會發佈一個新問題。 – Beaker 2013-05-04 19:19:42

+3

一個提示:您應該總是使用LookupSymbols來實現這樣的功能,因爲您還需要確保該方法在呼叫站點可以訪問。 LookupSymbols這樣做,而GetMembers不會。 – 2013-05-05 03:59:51