2012-02-17 13 views
5

MethodDeclarationSyntaxオブジェクトを指定すると、メソッドの宣言型をどのように見つけることができますか?メソッドの宣言型の検索

私の実際の問題は、参照されたメソッドがインターフェイスメソッドを実装しているかどうかを調べる必要があることです。私は廃棄()方法MethodDeclarationSyntaxを持っている場合、コード蛇腹所与例えば

、どのように)(これは、IDisposable.Disposeの実装であると結論することができますか?

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

ノー成功とメソッドの宣言タイプを(とタイプを確認してください)(親プロパティが私に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

+0

@svick:Equalsの順序を入れ替えるのは良い点です。 Roslynチームで開発した重要な習慣であるEqualsの私の使用は、偶然ではありません。==を使用すると、言語固有の型を使用している限り正常に動作します。 2つのIMethodSymbolsがある場合は、その場合に==がオーバーロードされないため、Equalsを使用する必要があります。 –

+0

@Jason私はあなたのコードで、あなたがDispose()メソッドのシンボルへの参照を取得して比較する必要がある方法を知っていると仮定しているので、これは私を助けません。もちろん、基本クラス/インターフェースを再帰的に(オブジェクトに到達するまで)チェックできますが、MethodSymbolクラスがこの情報を直接提供できると思います。 – Vagaus

4

構文タイプ(MethodDeclarationSyntaxなど)は、構文レベルでのみで動作します。このレベルでは、方法DisposeIDisposableを実装しているかどうかはわかりません。それはあなたがまだどのメソッドIDisposableを持っているか分からないからです。さらに、IDisposableが存在するかどうか、それがクラスであるかインターフェースであるか、またはそのフルネームが何であるかはわかりません。 (それはSystem.IDisposableか?MyNamespace.IDisposable?)

このような情報を得るには、推測したように、意味レベルに到達する必要があります。

明示的なインターフェイス実装でない限り、メソッドから直接インターフェイスにアクセスする方法が見つかりませんでした(EDIT:これは常に可能ではないため、Kevinのコメントを参照してください)。しかし、ある種のインタフェースメソッドの実装には、型から得ることができます。

あなたは、特定のMethodSymbolIDisposable.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

この方法でこれを行うことができない理由は、時にはわからないことがあるからです。 'Base {public void Dispose()} class Derived:Base、IDisposable {}'を持っていれば、Derived_のインスタンスを持っていれば実装されますが、Baseのインスタンスがある場合は... –

+0

うーん、私はそれが可能でもあり、興味深いことも気付かなかった。 – svick