查找方法的声明类型

时间:2012-02-17 20:00:03

标签: c# .net roslyn

给定MethodDeclarationSyntax对象,如何找出方法的声明类型?

我的实际问题是我需要弄清楚引用的方法是否正在实现接口方法。

例如,给定下面的代码,如果我有 Dispose()方法的MethodDeclarationSyntax,那么如何判断它是IDisposable.Dispose()的实现?

using System;
abstract class InterfaceImplementation : IDisposable
{
    public abstract void Dispose();
}

我试图获取方法的声明类型(并检查类型)但没有成功(Parent属性让我回到InterfaceImplementation类)。

我也试图抓住方法的语义符号:

var methodSymbol = (MethodSymbol) semanticModel.GetDeclaredSymbol(methodDeclaration);

但无法发现任何可以帮助我的事情。

想法?

2 个答案:

答案 0 :(得分:7)

获得方法符号后,您可以询问给定方法是否在给定类型中实现接口方法。代码很简单:

MethodSymbol method = ...;
TypeSymbol type = method.ContainingType;
MethodSymbol disposeMethod = (MethodSymbol)c.GetSpecialType(SpecialType.System_IDisposable).GetMembers("Dispose").Single();
bool isDisposeMethod = method.Equals(type.FindImplementationForInterfaceMember(disposeMethod));

重要的是要注意这假设包含Dispose方法的类型是声明它实现IDisposable的类型。在C#中,一个方法可以实现一个仅在派生类型上声明的接口方法。更具体地说,如果您在上面的代码中省略了“:IDisposable”,并且具有IDIisposable的派生类型的InterfaceImplementation,那么Dispose()方法仍然可以实现它。

答案 1 :(得分:4)

语法类型(如MethodDeclarationSyntax)在语法层面上只运行 。在此级别,不知道方法Dispose是否实现IDisposable。那是因为您还不知道IDisposable有哪些方法。更重要的是,你甚至不知道IDisposable是否存在,无论是类还是接口,还是它的全名。 (是System.IDisposable还是MyNamespace.IDisposable?)

要获得这样的信息,您需要达到语义级别,正如您猜测的那样。

我没有找到任何方法直接从方法到接口,除非它是一个显式的接口实现(编辑:那是因为它并不总是可行,请参阅Kevin的评论)。但是你可以从一个类型到一些特定的接口方法的实现。

因此,如果您想了解某个MethodSymbol实施IDisposable.Dispose(),您可以执行以下操作:

SyntaxTree unit = SyntaxTree.ParseCompilationUnit(code);

MethodDeclarationSyntax method = …;

var compilation = Compilation.Create("test")
    .AddReferences(new AssemblyFileReference(typeof(object).Assembly.Location))
    .AddSyntaxTrees(unit);

SemanticModel model = compilation.GetSemanticModel(unit);

MethodSymbol methodSymbol = (MethodSymbol)model.GetDeclaredSymbol(method);

var typeSymbol = methodSymbol.ContainingType;

var idisposableDisposeSymbol = model.BindExpression(
    0, Syntax.ParseExpression("System.IDisposable.Dispose()")).Symbol;

var implementation = typeSymbol.FindImplementationForInterfaceMember(
    idisposableDisposeSymbol);

bool methodImplementsDispose = methodSymbol == implementation;