我正在尝试在调用方法IBus.Publish<T>
的解决方案中找到所有位置(来自NServiceBus)。到目前为止,这是有效的:
IMethodSymbol method = ... [IBus.Publish methodsymbol resolved];
var callers = method.FindCallers(solution, new CancellationToken());
这导致IEnumerable<SymbolCallerInfo>
,我得到了对此方法的所有正确引用。
我现在怎样才能调用泛型参数IBus.Publish
?我是否必须手动解析sourcetree,还是存在一些我可以利用的Roslyn魔法?
示例:
在我的代码中,我有:
IBus _bus;
_bus.Publish<IMyMessage>(msg => { msg.Text = "Hello world"});
我对获取IMyMessage
类型感兴趣。
非常感谢帮助!
答案 0 :(得分:3)
您可以使用SemanticModel
从调用的SyntaxNode
转到实际的MethodSymbol
,然后您只需阅读TypeArguments
属性即可获取TypeSymbol
{1}}用于参数。如果没有明确指定参数,这甚至可以工作,因为SemanticModel
将执行类型推断。
例如:
var callers = method.FindCallers(solution, CancellationToken.None);
foreach (var caller in callers)
{
foreach (var location in caller.Locations)
{
if (location.IsInSource)
{
var callerSemanticModel = solution
.GetDocument(location.SourceTree)
.GetSemanticModel();
var node = location.SourceTree.GetRoot()
.FindToken(location.SourceSpan.Start)
.Parent;
var symbolInfo = callerSemanticModel.GetSymbolInfo(node);
var calledMethod = symbolInfo.Symbol as IMethodSymbol;
if (calledMethod != null)
{
var arguments = calledMethod.TypeArguments;
}
}
}
}
答案 1 :(得分:1)
我对IMethodSymbol和ISymbol接口并不熟悉,但这是另一种从InvocationExpressionSyntax
获取通用参数的方法
var methodRef = (InvocationExpressionSyntax)find_method();
var genericArguments = methodRef.DescendantNodes().OfType<GenericNameSyntax>().FirstOrDefault();
if (genericArguments != null)
foreach (var g_arg in genericArguments.TypeArgumentList.Arguments)
Console.WriteLine(g_arg);
static InvocationExpressionSyntax find_method()
{
var code = new StreamReader("..\\..\\Tests.cs").ReadToEnd();
SyntaxTree tree = SyntaxTree.ParseText(code);
var root = tree.GetRoot();
//find your methods here
return (InvocationExpressionSyntax)root.DescendantNodes().ToArray()[88];
}