2012-02-17 67 views
5

给定一个MethodDeclarationSyntax对象,我该如何找出该方法的声明类型?找到一个方法的声明类型

我的实际问题是,我需要弄清楚引用的方法是否正在实现接口方法。例如,给定代码如下,如果我有一个MethodDeclarationSyntax的Dispose()方法,如何可以得出结论它是IDisposable.Dispose()的实现?

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

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

我也想抓该方法的语义符号:

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

,但不能发现任何东西,可以帮助我。

想法?

回答

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”,并且派生了一个IDisposable的InterfaceImplementation类型,那么Dispose()方法仍然可以实现它。

+0

因为'FindImplementationForInterfaceMember()'可以返回'null',所以我会在这里使用'=='运算符而不是'Equals()'。或者至少用另一种方式写出Equals()。 – svick 2012-02-17 22:29:53

+0

@svick:交换Equals排序的好处。我对Equals的使用并非偶然,因为我们已经在Roslyn团队开发了一个重要习惯:只要您只使用特定于语言的类型,using ==就可以正常工作。如果你有两个IMethodSymbols,你*必须*使用Equals,因为==在这种情况下不会被重载。 – 2012-02-17 22:35:30

+0

@Jason我恐怕这不会帮助我,因为它假定我知道我需要检查什么方法(在您的代码中,您获取对Dispose()方法符号的引用并与之进行比较),而不是这种情况。当然,我可以递归地检查基类/接口(直到我到达对象),但我会期望MethodSymbol类可以直接提供给我这些信息。 – Vagaus 2012-02-20 18:38:24

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; 
+1

你不能从该方法做到这一点的原因是,有时你不知道。如果你有'class Base {public void Dispose()} class Derived:Base,IDisposable {}'那么“Dispose”就是实现_if你有一个Derived_的实例,但是如果你有一个Base的实例... – 2012-02-17 22:30:03

+0

嗯,我没有意识到这甚至是可能的,有趣的。 – svick 2012-02-17 22:34:37