2016-06-14 7 views
2

Zum Beispiel Aufruf:Roslyn: Analysieren des Objekts, das Verfahren

SqlCommand command = new SqlCommand(); 
SqlDataReader datareader = command.ExecuteReader(); 

Der Aufrufknoten ist hier command.ExecuteReader(). Wie kann ich mit roslyn den Variablenbezeichner token/node von command vom Aufrufknoten erhalten? Angenommen, dieser Aufrufknoten kann viele andere Methodenaufrufe davor haben, z. classA.methodA().methodB().classB.methodC(command.ExecuteReader()) und daher Bezeichner durch node.DescendantNodes möglicherweise nicht nützlich sein. Die Lösung, an die ich dachte, war, zuerst den SpanStart von ExecuteReader zu bekommen, dann das Symbol von command durch Aufruf von SymbolFinder.FindSymbolAtPosition mit der Position ExecuteReader.SpanStart - 2. Ich bin jedoch unsicher, ob diese Lösung jede einzelne Situation bewältigen kann. Die Anwendung, an der ich arbeite, ist ein statischer Code-Analysator.

+3

Am Ende diejenigen sind nur angekettet Anrufungen/einfaches Mitglied zugreift. Wenn Sie den innersten Aufruf (oder 'SimpleMemberAccessExpression') erhalten, haben Sie, was Sie wollen. Betrachte den unmittelbaren Elternteil anstelle aller Vorfahren. –

+0

gibt es da einen besseren Weg, anstatt es hart zu codieren? B. das Symbol des Methodenaufrufs ermitteln und dann anhand des Symbols die Instanz eines Objekts ermitteln, das die Methode aufruft. zum Beispiel: 'ClassA varA = new ClassA(); varA.methodA() 'get symbol von' methodA() 'und herauszufinden, dass' varA' es aufgerufen hat. –

+0

Was meinst du mit "hart codieren"? Wenn Sie diesen Aufruf wünschen, müssen Sie Code schreiben, der den Aufruf erhält. –

Antwort

4

Wenn Sie einen Aufrufknoten haben, können Sie sehen, ob es sich bei dem Ausdruck um einen Mitgliederzugriff handelt oder nicht. Wenn der Aufruf für eine Anweisung "DoThis()" ist, dann gibt es keinen Mitgliederzugriff, aber wenn der Aufruf für "x.DoThis()" ist, dann ist ein Mitgliederzugriff, da "DoThis" aufgerufen wird Referenz "x".

Sobald Sie bestätigen, dass ein Mitglied Zugriff ist, können Sie dann den Ausdruck der Zielreferenz erhalten - das ist die Referenz, auf deren Mitglied zugegriffen wird. Dieser Ausdruck kann ein einfacher Namensbezeichner sein (zB "Befehl") oder ein anderer Mitgliedszugriff (zB "x.command") oder ein anderer Aufruf (zB "GetCommand()") oder es könnte sein eine Kombination von diesen.

mit Code zu veranschaulichen -

private static void AnalyseInvocation(SyntaxNodeAnalysisContext context) 
{ 
    var invocation = (InvocationExpressionSyntax)context.Node; 
    var memberAccess = invocation.Expression as MemberAccessExpressionSyntax; 
    if ((memberAccess == null) || (memberAccess.Name.Identifier.ValueText != "ExecuteReader")) 
     return; 

    if (memberAccess.Expression is IdentifierNameSyntax) 
    { 
     // The target is a simple identifier, the code being analysed is of the form 
     // "command.ExecuteReader()" and memberAccess.Expression is the "command" 
     // node 
    } 
    else if (memberAccess.Expression is InvocationExpressionSyntax) 
    { 
     // The target is another invocation, the code being analysed is of the form 
     // "GetCommand().ExecuteReader()" and memberAccess.Expression is the 
     // "GetCommand()" node 
    } 
    else if (memberAccess.Expression is MemberAccessExpressionSyntax) 
    { 
     // The target is a member access, the code being analysed is of the form 
     // "x.Command.ExecuteReader()" and memberAccess.Expression is the "x.Command" 
     // node 
    } 
} 
+0

hmm..aber wenn es eine lange Kette von Aufrufausdruck wird es immer noch funktionieren? zum Beispiel 'node.ChildNodes(). OfType (). Single(). Name', aus dem Syntax Visualizer in Visual Studio, ist der Aufruf.Express von Single()' node.ChildNodes(). OfType < MemberAccessExpressionSyntax>(). Single ', die aus dem Syntax-Visualizer eine' MemberAccessExpressionSyntax' ist und daher nicht die Bedingung von "x.Command.ExecuteReader()" erfüllt, korrigiere mich, wenn ich falsch bin. Vielen Dank! und Entschuldigung für die sehr späte Antwort. lol. –

+0

Entschuldigung, ich denke, ich habe Ihren Code missverstanden, so dass Sie 'invocation.Expression.Expression' überprüfen, richtig? dann in diesem Fall denke ich, du bist richtig auf dem Ansatz –

+0

@KimKangIn ja, ich bin im Wesentlichen Überprüfung Aufruf.Expression.Expression - dies wird die gesamte Kette vor dem Aufruf "ExecuteReader" zurückgeben, egal wie einfach oder komplex diese Kette ist. Ich habe das Codebeispiel leicht geändert, um jeden Aufruf zu ignorieren, der nicht für "ExecuteReader" ist. Wenn Sie also diesen Code in der IDE ausführen und einen Haltepunkt für die erste "if (memberAccess.Expression is .." - Zeile setzen, dann Sie werden sehen, indem Sie die memberAccess-Referenz überprüfen, dass es immer * alles * vor "ExecuteReader" im Aufruf ist. –

Verwandte Themen