2012-02-17 68 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