如何在方法调用时查找方法参数的类型?
How to find the types of method arguments upon method call?
假设我们有以下基本模型:
public class Base
{
...
}
并且有M1, ..., Mn 模型来源于此。
我们有一个具有以下结构的接口:
public interface IExampleInterface
{
void DoSomething(Base input);
}
假设我们对此有一个简单的实现 class,例如:
public class Example : IExampleInterface
{
void DoSomething(Base input)
{
System.Console.WriteLine("Please help me!!");
}
}
IExampleInterface.DoSomething 方法在整个解决方案中使用不同的输入参数进行多次调用。
var ex = new Example();
var m = new M();
ex.DoSometing(m);
其中 M 可以是来自 M1, ..., Mn[=48= 的任何类型].
我设法从语法树中找到了接口,它的实现和参数类型,甚至我找到了调用者,但是我在[=33=中找不到传递参数的类型]IExampleInterface.DoSomething来电。
代码如下:
var interfaceName = "IExampleInterface";
var returnType = "Void";
var methodName = "DoSomething";
var arg = "Base";
var exInterface = compilations
.SelectMany(compilation => compilation.SyntaxTrees.Select(syntaxTree => compilation.GetSemanticModel(syntaxTree)))
.SelectMany(
semanticModel => semanticModel
.SyntaxTree
.GetRoot()
.DescendantNodes()
.OfType<InterfaceDeclarationSyntax>()
.Select(interfaceDeclarationSyntax => semanticModel.GetDeclaredSymbol(interfaceDeclarationSyntax)))
.Where(s => s.Name == interfaceName)
.FirstOrDefault();
var implementations = await SymbolFinder.FindImplementationsAsync(exInterface, solution);
var implementation = implementations.FirstOrDefault() as ITypeSymbol;
var method = exInterface
.GetMembers(methodName)
.Where(m => m.Kind == SymbolKind.Method)
.Cast<IMethodSymbol>()
.FirstOrDefault(m =>
m.Parameters != null &&
m.Parameters.Length == 1 &&
m.Parameters[0].Type.Name == arg &&
m.ReturnType.Name == returnType);
var callers = await SymbolFinder.FindCallersAsync(method, solution);
此时我卡住了。我对 Roslyn 比较陌生。我的问题是如何找到传递给 IExampleInterface.DoSomething 调用的参数类型?
我实际上通过获取编译的语义模型解决了这个问题。
首先,在找到所有调用者之后,我们需要在 [=19 的帮助下找到 InvocationExpression 节点=]CallingSymbol 来自 SymbolCallerInfo.
其次,我们必须从ArgumentList 属性 of [中得到我们感兴趣的参数InvocationExpression.
假设 arg 是所需的参数并且 compilation 是 arg 来自的编译实例。
var type = compilation
.GetSemanticModel(arg.SyntaxTree)
.GetTypeInfo(arg.ChildNodes().First());
假设我们有以下基本模型:
public class Base
{
...
}
并且有M1, ..., Mn 模型来源于此。
我们有一个具有以下结构的接口:
public interface IExampleInterface
{
void DoSomething(Base input);
}
假设我们对此有一个简单的实现 class,例如:
public class Example : IExampleInterface
{
void DoSomething(Base input)
{
System.Console.WriteLine("Please help me!!");
}
}
IExampleInterface.DoSomething 方法在整个解决方案中使用不同的输入参数进行多次调用。
var ex = new Example();
var m = new M();
ex.DoSometing(m);
其中 M 可以是来自 M1, ..., Mn[=48= 的任何类型].
我设法从语法树中找到了接口,它的实现和参数类型,甚至我找到了调用者,但是我在[=33=中找不到传递参数的类型]IExampleInterface.DoSomething来电。
代码如下:
var interfaceName = "IExampleInterface";
var returnType = "Void";
var methodName = "DoSomething";
var arg = "Base";
var exInterface = compilations
.SelectMany(compilation => compilation.SyntaxTrees.Select(syntaxTree => compilation.GetSemanticModel(syntaxTree)))
.SelectMany(
semanticModel => semanticModel
.SyntaxTree
.GetRoot()
.DescendantNodes()
.OfType<InterfaceDeclarationSyntax>()
.Select(interfaceDeclarationSyntax => semanticModel.GetDeclaredSymbol(interfaceDeclarationSyntax)))
.Where(s => s.Name == interfaceName)
.FirstOrDefault();
var implementations = await SymbolFinder.FindImplementationsAsync(exInterface, solution);
var implementation = implementations.FirstOrDefault() as ITypeSymbol;
var method = exInterface
.GetMembers(methodName)
.Where(m => m.Kind == SymbolKind.Method)
.Cast<IMethodSymbol>()
.FirstOrDefault(m =>
m.Parameters != null &&
m.Parameters.Length == 1 &&
m.Parameters[0].Type.Name == arg &&
m.ReturnType.Name == returnType);
var callers = await SymbolFinder.FindCallersAsync(method, solution);
此时我卡住了。我对 Roslyn 比较陌生。我的问题是如何找到传递给 IExampleInterface.DoSomething 调用的参数类型?
我实际上通过获取编译的语义模型解决了这个问题。
首先,在找到所有调用者之后,我们需要在 [=19 的帮助下找到 InvocationExpression 节点=]CallingSymbol 来自 SymbolCallerInfo.
其次,我们必须从ArgumentList 属性 of [中得到我们感兴趣的参数InvocationExpression.
假设 arg 是所需的参数并且 compilation 是 arg 来自的编译实例。
var type = compilation
.GetSemanticModel(arg.SyntaxTree)
.GetTypeInfo(arg.ChildNodes().First());