Как получить базовый тип для конкретного типа - PullRequest
0 голосов
/ 08 ноября 2018

Я работаю над анализатором кода C # и использую Roslyn (.NET Compiler API).

И я хотел бы проверить, что определенный тип наследуется от типа базового класса.

Например, предположим, у нас есть иерархия пользовательских классов:

TypeA -> TypeB -> TypeC -> TypeD

Где TypeA является родительским классом для TypeB, TypeB является родительским для TypeC, а TypeC является родительским для TypeD.

Я создал метод:

    bool InheritsFrom(ITypeSymbol symbol, string expectedParentTypeName)
    {
        while (true)
        {
            if (symbol.ToString().Equals(expectedParentTypeName))
            {
                return true;
            }

            if (symbol.BaseType != null)
            {
                symbol = symbol.BaseType;
                continue;
            }
            break;
        }

        return false;
    }

symbol содержит тип, который необходимо проверить. Но этот подход не работает. Код не получает родительский тип для символа.

symbol.BaseType возвращает один и тот же тип класса дважды, а затем (на следующей итерации) я получаю symbol.BaseType, равный null.

expectedParentTypeName содержит полное имя типа: например, some.namespace.blablabla.TypeC

Как мне решить эту задачу?


Обновление

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

TypeA -> TypeB -> TypeC -> TypeD

После анализа я получаю свойство с типом TypeD и хочу проверить, что оно наследуется от TypeB


Обновление № 2

TypeA -> TypeB -> TypeC -> TypeD типов еще не существует , когда я пишу свой анализатор кода. Поэтому я не могу использовать typeof и другие вещи для этих типов.

Они будут существовать только в контексте, в котором будет работать анализатор.

Мой анализатор получает часть исходного кода, распознает его как имя типа, и я хочу проверить, что это распознанное имя типа унаследовано от другого пользовательского типа, импортированного из пакета custom nuget.

Все, что у меня есть - у меня есть исходный код для анализа и имена этих пользовательских типов в объявлениях класса, свойства, поля и т. Д.


Обновление № 3

Для следующего кода:

SyntaxNodeAnalysisContext context; // is already initialized 

PropertyDeclarationSyntax propertyDeclaration = (PropertyDeclarationSyntax)context.Node;

ClassDeclarationSyntax classDeclaration = (ClassDeclarationSyntax) propertyDeclaration.Parent;

TypeInfo propertyTypeInfo = context.SemanticModel.GetTypeInfo(propertyDeclaration);

TypeInfo classTypeInfo = context.SemanticModel.GetTypeInfo(classDeclaration);

propertyTypeInfo и classTypeInfo не содержат никакой информации внутри.

enter image description here

Ответы [ 3 ]

0 голосов
/ 08 ноября 2018

Существуют способы (упоминаемые в других вопросах стека) для создания объекта из typename во время выполнения. (Здесь есть несколько полезных фрагментов кода: с использованием типа, возвращаемого Type.GetType () в c # )

Затем вы можете получить объект вашего symbol и проверить, передан ли он того типа.

if (symbolObject is typeClassWorkedOutAbove)
{
    //do stuff
}
0 голосов
/ 08 ноября 2018
  1. ITypeSymbol.BaseType - это именно то, что вам нужно для получения базового типа. BaseType может быть нулевым, если ваш тип System.Object, интерфейс или тип указателя, также, если у вас есть пара проблем с семантической логикой в ​​вашем Compilation, это может быть тип ошибки, что означает, что вы что-то пропустили, ссылаясь на Roslyn не может определенно разрешить типы. В другом случае symbol.BaseType должно работать очень хорошо по умолчанию. Поэтому я предлагаю вам проверить свой символ и проверить диагностику в Compilation

  2. ITypeSymbol.ToString() вернет строку, которая будет построена с помощью CSharpErrorMessageFormat , которая имеет стиль типа FQN, достаточный для вашего вопроса. Если вы хотите больше, вы можете передать пользовательский SymbolDisplayFormat на ToDisplayString

  3. Для узлов объявления SemanticModel.GetTypeInfo вернет значения NULL TypeSymbol и ConvertedSymbol, вместо этого вы должны использовать SemanticModel.GetDeclaredSymbol

    var propertyTypeSymbol = context.SemanticModel.GetDeclaredSymbol(propertyDeclaration) as ITypeSymbol;
    var classTypeSymbol = context.SemanticModel.GetDeclaredSymbol(classDeclaration) as ITypeSymbol;
    

    P.S. будьте осторожны, используйте GetDeclaredSymbol для некоторых специальных узлов объявления: например, FieldDeclarationSyntax)

0 голосов
/ 08 ноября 2018

Просто is?

if(DerivedType is BaseType)
{
    //Party time
}
...