Я пишу анализатор Roslyn, который должен проверить, был ли параметр метода, объявленный с атрибутом [NotNull] в текущем объявлении метода или в одном из интерфейсов, и выполнить некоторые проверки его тела метода.Я зарегистрировал CodeBlockAction с помощью RegisterCodeBlockAction, но когда я пытаюсь получить атрибуты из объявления параметров в интерфейсах / базовых классах, в которых он есть, иногда он возвращает пустой массив.
Я обнаружил, что это происходит в случае, если интерфейсКласс / base находится в другой сборке, и на самом деле анализатор работает нормально, когда Intelisense запускает его, но в выводе сборки нет предупреждений \ ошибок.Я думаю, что это происходит из-за того, что семантический анализ ссылочной сборки не завершен полностью (но это немного странно).
Я написал несколько журналов
6/6/2019 13:59:47 Analize method symbol "ClassLibrary1.Program.Foo(string)" with 1 interfaces
6/6/2019 13:59:47 declaration ClassLibrary2.IFoo.Foo(string): [0 attributes] string s
6/6/2019 13:59:47 declaration ClassLibrary1.Program.Foo(string): [0 attributes] string s
6/6/2019 13:59:59 Analize method symbol "ClassLibrary1.Program.Foo(string)" with 1 interfaces
6/6/2019 13:59:59 declaration ClassLibrary2.IFoo.Foo(string): [1 attributes] string s
6/6/2019 13:59:59 declaration ClassLibrary1.Program.Foo(string): [0 attributes] string s
Итак, вы можете видеть, что в 13: 59: 47 (запуск msbuild) атрибутов нет, но в 13:59:59 (я открыл документ в Visual studio) есть один атрибут.
Есть способ получить интерфейс и параметры:
var allMethodDeclarations = //some code using methodSymbol.ContainingType.Interfaces
for (var i = 0; i < methodSymbol.Parameters.Length; ++i)
{
var currentParameter = methodSymbol.Parameters[i];
//parameters can be renamed, the only way is to use the order
var hasNotNull = allMethodDeclarations
.Select(d => d.Parameters[i])
.SelectMany(p => p.GetAttributes())
.Any(a => a.AttributeClass.Name == nameof(NotNullAttribute));
if (hasNotNull)
{
//do something
}
}
Пример кода, на котором воспроизводится ошибка:
В сборке 1
public interface IFoo
{
void Foo([NotNull] string s);
}
В сборке 2 эта ссылка ссылается на сборку 1
public class Program : IFoo
{
public void Foo(string s)
{
}
}