2012-02-17 2 views
5

MethodDeclarationSyntax 개체가 주어지면 메서드의 선언 형식을 어떻게 알 수 있습니까?메서드의 선언 형식 찾기

내 실제 문제는 참조 된 메소드가 인터페이스 메소드를 구현하는지 여부를 알아 내야한다는 것입니다.

예를 들어, Dispose() 메서드에 대한 MethodDeclarationSyntax가있는 경우 코드를 지정하면 어떻게 IDisposable.Dispose()를 구현할 수 있습니까?

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

내가 메소드의 선언 형식을 얻을 수 (및 유형 검사)없이 성공을 위해 노력했습니다 (부모 속성은 InterfaceImplementation 클래스를 날 다시 제공).

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

을하지만, 나에게 도움이 될 수 아무것도 발견하지 못했습니다 :

나는 또한 방법에 대한 의미 론적 기호를 잡기 위해 노력했다.

아이디어가 있으십니까?

답변

7

, 당신은 요청할 수 있습니다 : 당신이 특정 MethodSymbolIDisposable.Dispose() 구현하는 것을 찾으려면

그래서, 당신은 뭔가를 할 수 메서드를 호출합니다. 코드는 매우 간단하다 :

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

그것은이이 폐기 방법을 포함하는 유형을 가정에 유의하는 것이 중요합니다 그것으로 IDisposable을 구현하는 내용의 유형입니다. C#에서는 메서드가 파생 된 형식에 대해서만 언급 된 인터페이스 메서드를 구현할 수 있습니다. 보다 구체적으로, 위의 코드에서 ": IDisposable"을 생략하고 IDisposable 인 파생 된 InterfaceImplementation 유형이있는 경우 Dispose() 메서드는 여전히이를 구현할 수 있습니다.

+0

'FindImplementationForInterfaceMember()'가'null'을 반환 할 수 있기 때문에'Equals()'대신에'=='연산자를 사용합니다. 또는 적어도 'Equals()'를 다른 방법으로 써라. – svick

+0

@svick : 동등 주문을 교환 할 때 좋은 점. Roslyn 팀에서 개발 한 중요한 습관 인 Equals를 사용하는 것은 우연이 아닙니다. 언어 별 유형 만 사용하는 경우 ==를 사용하면 문제가 없습니다. IMethodSymbols가 두 개인 경우에는 ==이 과부하되지 않으므로 같음을 사용해야합니다. –

+0

@ Jason이 방법은 내가 확인해야 할 메소드가 무엇인지 알고 있다고 가정하고 나에게 도움이되지 않을까 걱정됩니다. 코드에서 Dispose() 메소드 심볼에 대한 참조를 가져 와서 비교합니다. 물론 (객체에 도달 할 때까지) 기본 클래스/인터페이스를 재귀 적으로 확인할 수 있지만 MethodSymbol 클래스가이 정보를 직접 제공 할 것으로 기대합니다. – Vagaus

4

구문 유형 (예 : MethodDeclarationSyntax)은 의 구문 수준에서 만 작동합니다. 이 수준에서는 Dispose 메서드가 IDisposable을 구현하는지 여부는 알 수 없습니다. 그 이유는 당신이 아직 어떤 방법으로 IDisposable을 가지고 있는지 모르기 때문입니다. 더구나 심지어 IDisposable이 있는지 여부, 클래스인지 인터페이스인지 또는 전체 이름인지 알지 못합니다. (System.IDisposable 또는 MyNamespace.IDisposable?)

이와 같은 정보를 얻으려면 사용자가 추측 한대로 의미 론적 수준에 도달해야합니다.

명시 적 인터페이스 구현이 아닌 한 인터페이스에서 직접 메소드를 가져올 방법을 찾지 못했습니다 (EDIT : 항상 가능하지 않기 때문에 Kevin의 설명 참조). 그러나 특정 인터페이스 메소드의 구현에서 유형을 얻을 수 있습니다. 당신이 방법 기호가 있으면 주어진 방법은 인터페이스를 구현하는 경우

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

당신이 방법에서 이것을 할 수없는 이유는 때때로 당신이 말할 수 없다는 것입니다. 클래스베이스 {public void Dispose()} 클래스가 파생 된 경우 : Base, IDisposable {}'그런 다음 Base의 인스턴스가있는 경우가 아니라 Derived_ 인스턴스가있는 경우 "Dispose"가 구현됩니다. –

+0

흠, 그게 가능할지 모르겠다. 흥미 롭다. – svick