2016-01-12 2 views
4

Каков наилучший способ общего назначения для получения System.Type из Microsoft.CodeAnalysis.ISymbol для разных типов символов? (например, объявления классов, переменные, свойства и т. д.)Получение типа из символа в roslyn

Я хочу иметь возможность выполнять различные проверки типа, например. как проверяет, реализует ли какой-либо интерфейс какой-либо интерфейс или может ли он использовать какой-либо интерфейс, точно так же, как можно проверить на System.Type.

Проблема, с которой я сталкиваюсь, заключается в том, что большинство конкретных классов, используемых для представления символа, являются внутренними (см. http://source.roslyn.io/), и я не мог найти информацию типа tye в ISymbol.

  • SourceNamedTypeSymbol
  • LocalSymbol

Я извлечь ISymbol используя следующий код

var objectSymbol = (ISymbol)model.GetDeclaredSymbol(obj.Node); 
+0

Вы ищете 'INamedTypeSymbol' – SLaks

ответ

8

Короткий ответ: вы не можете. Нет подходящего способа получить System.Type (отражение) от ISymbol (Roslyn).

Один вариант сделать в нужном вам направлении - это построить полное имя вашего типа, а затем посмотреть, что происходит через отражение (example).

Возможно, вы должны спросить себя, действительно ли это то, что вам нужно сделать в первую очередь, хотя отражение и Рослин на самом деле не предназначены для совместной работы.

То, что вас интересует, однако, может быть сделано через Roslyn. Ключевым моментом здесь является использование семантической модели, которая имеет всю эту информацию для вас. Все объявления (в отличие от обычаев) имеют определенную перегрузку, позволяющую получить символ объявления и вернуть его в соответствующем типе (например, INamedTypeSymbol).

Рассмотрим следующий пример:

const string source = @" 
using System; 

namespace MyNamespace 
{ 
    class MyClass : IDisposable 
    { 
     void Method() 
     { 
      MyClass nameOfVariable, another; 
     } 
    } 
} 
"; 
var tree = CSharpSyntaxTree.ParseText(source); 
var compilation = CSharpCompilation.Create("MyCompilation", new[] { tree }, new[] { MetadataReference.CreateFromFile(typeof(object).Assembly.Location) }); 
var semanticModel = compilation.GetSemanticModel(tree); 
var root = tree.GetRoot(); 

var classSymbol = semanticModel.GetDeclaredSymbol(root.DescendantNodes().OfType<ClassDeclarationSyntax>().First()); 
Console.WriteLine(string.Join(", ", classSymbol.AllInterfaces)); 

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

В вашем случае вы должны быть в состоянии просто бросить его на правильный тип (предполагается, что вы проверяете узел декларации):

var objectSymbol = (INamedTypeSymbol) model.GetDeclaredSymbol(obj.Node); 
+0

Спасибо за ответ, и я смог добиться результата! – antiskidwarpdrive

+4

И подчеркнуть, почему нет простого способа: вполне возможно, что вы не сможете его получить. Единственный способ получить System.Type - это отразить загрузку рассматриваемой сборки, но на самом деле у вас может не быть загружаемой сборки. Принципиальное отражение - это API времени выполнения, а время выполнения и время компиляции - разные вещи. Лучше всего использовать API Roslyn, как описывает фантастический ответ Джереена. –