Нахождение типа объявления метода - PullRequest
5 голосов
/ 18 февраля 2012

С учетом объекта MethodDeclarationSyntax как я могу узнать тип объявления метода?

Моя настоящая проблема заключается в том, что мне нужно выяснить, реализует ли ссылочный метод метод интерфейса или нет.

Например, учитывая приведенный ниже код, если у меня есть метод MethodDeclarationSyntax для метода Dispose () , как можно сделать вывод, что это реализация IDisposable.Dispose ()?

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

Я попытался получить тип объявления метода (и проверить тип) безуспешно (свойство Parent возвращает мне интерфейс InterfaceImplementation).

Я также попытался получить семантический символ для метода:

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

но не смог найти ничего, что могло бы мне помочь.

Идеи?

Ответы [ 2 ]

8 голосов
/ 18 февраля 2012

Получив символ метода, вы можете спросить, реализует ли данный метод интерфейсный метод в рамках данного типа.Код довольно прост:

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» в своем коде выше и имеете производный тип InterfaceImplementation, который был IDisposable, этот метод Dispose () все еще может реализовать его.

4 голосов
/ 18 февраля 2012

Синтаксические типы (например, MethodDeclarationSyntax) работают только на на синтаксическом уровне. На этом уровне не известно, реализует ли метод Dispose IDisposable. Это потому, что вы еще не знаете, какие методы есть у IDisposable. Более того, вы даже не знаете, существует ли IDisposable, является ли он классом или интерфейсом, или каково его полное имя. (Это System.IDisposable? Или MyNamespace.IDisposable?)

Чтобы получить такую ​​информацию, вам нужно перейти на семантический уровень, как вы уже догадались.

Я не нашел способа напрямую перейти от метода к интерфейсу, если это не явная реализация интерфейса (РЕДАКТИРОВАТЬ: это потому, что это не всегда возможно, см. Комментарий Кевина). Но вы можете перейти от типа к реализации определенного метода интерфейса.

Итак, если вы хотите узнать, что определенный 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;
...