在Roslyn中获取SymbolCallerInfo的泛型参数

时间:2013-10-16 07:15:41

标签: c# generics roslyn

我正在尝试在调用方法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类型感兴趣。

非常感谢帮助!

2 个答案:

答案 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];
}