Пользовательские Предупреждения Компилятора


при использовании ObsoleteAtribute в .Net он дает вам предупреждения компилятора, сообщающие вам, что объект/метод/свойство устарело и что-то еще должно использоваться. В настоящее время я работаю над проектом, который требует много рефакторинга кода бывших сотрудников. Я хочу написать пользовательский атрибут, который я могу использовать для пометки методов или свойств, которые будут генерировать предупреждения компилятора, которые дают сообщения, которые я пишу. Что-то вроде этого

[MyAttribute("This code sux and should be looked at")]
public void DoEverything()
{
}
<MyAttribute("This code sux and should be looked at")>
Public Sub DoEverything()
End Sub

Я хочу, чтобы это создать предупреждение компилятора, которое говорит:"этот код sux и должен быть рассмотрен". Я знаю, как создать пользовательский атрибут, вопрос в том, как заставить его генерировать предупреждения компилятора в visual studio.

11 102

11 ответов:

обновление

теперь это возможно с Roslyn (Visual Studio 2015). Вы можете построить a анализатор кода чтобы проверить наличие настраиваемого атрибута


Я не верю, что это возможно. Атрибут ObsoleteAttribute специально обрабатывается компилятором и определяется в стандарте C#. Почему на земле ObsoleteAttribute не приемлем? Мне кажется, что это именно та ситуация, для которой она была предназначена, и достигает именно того, что вы требуйте!

также обратите внимание, что Visual Studio собирает предупреждения, созданные ObsoleteAttribute на лету тоже, что очень полезно.

не хочу быть бесполезным, просто интересно, почему вы не хотите использовать его...

к сожалению ObsoleteAttribute запечатан (вероятно, частично из-за специального обращения), поэтому вы не можете подклассировать свой собственный атрибут из него.

из стандарта C#: -

атрибут устарел используется для обозначения типы и члены типов, которые должны больше не используется.

Если программа использует тип или член то есть украшен устаревшим атрибута, компилятор выдает предупреждение или ошибка. В частности, компилятор выдает предупреждение, если нет ошибки параметр предоставляется, или если ошибка параметр и имеет значение false. Компилятор выдает ошибка, если параметр ошибки указан и имеет значение истинный.

разве это не подводит итог вашим потребностям?... я не думаю, что ты сделаешь лучше, чем это.

не знаю, если это будет работать, но стоит попробовать.

вы не можете расширить устаревший, потому что его окончательный, но, возможно, вы можете создать свой собственный атрибут и пометить этот класс как устаревший следующим образом:

[Obsolete("Should be refactored")]
public class MustRefactor: System.Attribute{}

затем, когда вы отмечаете свои методы атрибутом "MustRefactor", могут отображаться предупреждения компиляции.

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

С уважением!

обновление: протестировано. Он генерирует предупреждение о времени компиляции, но сообщение об ошибке выглядит смешно, вы должны увидеть его сами и выбрать. Это очень близко к тому, что вы хотели достичь.

обновление 2: С код он генерирует это предупреждения (не очень приятно, но я не думаю, что есть что-то лучше).

public class User
{
    private String userName;

    [TooManyArgs] // Will show warning: Try removing some arguments
    public User(String userName)
    {
        this.userName = userName;   
    }

    public String UserName
    {
        get { return userName; }
    }
    [MustRefactor] // will show warning: Refactor is needed Here
    public override string ToString()
    {
        return "User: " + userName;
    }
}
[Obsolete("Refactor is needed Here")]
public class MustRefactor : System.Attribute
{

}
[Obsolete("Try removing some arguments")]
public class TooManyArgs : System.Attribute
{

}

в некоторых компиляторах вы можете использовать #warning для выдачи предупреждения:

#warning "Do not use ABC, which is deprecated. Use XYZ instead."

в компиляторах Microsoft, как правило, можно использовать сообщение pragma:

#pragma message ( "text" )

вы упомянули .Net, но не указали, программируете ли вы с помощью C/C++ или C#. Если вы программируете на C#, чем вы должны знать, что C# поддерживает формат # warning.

в настоящее время мы находимся в середине большого рефакторинга, где мы не могли исправить все сразу. Мы просто используем команду # warning preproc, где нам нужно вернуться и посмотреть на код. Он отображается в выходных данных компилятора. Я не думаю, что вы можете поместить его на метод, но вы можете поместить его только внутри метода, и его все еще легко найти.

public void DoEverything() {
   #warning "This code sucks"
}

в VS 2008 (+sp1) #предупреждения не отображаются должным образом в списке ошибок после решения Clean Soultion & Rebuild, нет всех из них. Некоторые предупреждения отображаются в списке ошибок только после открытия определенного файла класса. Поэтому я был вынужден использовать пользовательский атрибут:

[Obsolete("Mapping ToDo")]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property)]
public class MappingToDo : System.Attribute
{
    public string Comment = "";

    public MappingToDo(string comment)
    {
        Comment = comment;
    }

    public MappingToDo()
    {}
}

поэтому, когда я отмечаю какой-то код с ним

[MappingToDo("Some comment")]
public class MembershipHour : Entity
{
    // .....
}

он выдает такие предупреждения:

пространство имен.MappingToDo устарел: 'Сопоставление Тодо'.

Я не могу измените текст предупреждения, "некоторые комментарии" не показали его список ошибок. Но он будет прыгать в нужное место в файле. Поэтому, если вам нужно изменить такие предупреждающие сообщения, создайте различные атрибуты.

то, что вы пытаетесь сделать, это неправильное использование атрибутов. Вместо этого используйте список задач Visual Studio. Вы можете ввести комментарий в свой код следующим образом:

//TODO:  This code sux and should be looked at
public class SuckyClass(){
  //TODO:  Do something really sucky here!
}

затем откройте меню Вид / список задач. Список задач состоит из двух категорий: пользовательские задачи и комментарии. Переключитесь на комментарии, и вы увидите все ваши //Todo:'S там. Двойной щелчок по задаче приведет к переходу к комментарию в вашем коде.

Al

Я не думаю, что вы можете. Насколько я знаю, поддержка ObsoleteAttribute по существу жестко закодирована в компилятор C#; вы не можете сделать ничего подобного напрямую.

возможно, вы можете использовать задачу MSBuild (или событие после сборки), которое выполняет пользовательский инструмент для только что скомпилированной сборки. Пользовательский инструмент будет отражать все типы / методы в сборке и использовать ваш пользовательский атрибут, после чего он может печатать в системе.Консоль по умолчанию или ошибка Авторы текстов.

глядя на источник ObsoleteAttribute, не похоже, что он делает что-то особенное для генерации предупреждения компилятора, поэтому я бы предпочел пойти с @технофилов и говорят, что он жестко закодирован в компилятор. Есть ли причина, по которой вы не хотите просто использовать ObsoleteAttribute для создания предупреждающих сообщений?

есть несколько комментариев, которые предлагают вставить предупреждения или pragma. Устаревшие работы совсем по-другому! Помечая устаревшую функцию библиотеки L, устаревшее сообщение возникает, когда программа вызывает функцию, даже если вызывающая программа не находится в библиотеке L. предупреждение вызывает сообщение только при компиляции L.

вот реализация Roslyn, так что вы можете создать свои собственные атрибуты, которые дают предупреждения или ошибки мухи.

Я создал тип атрибута под названием IdeMessage, который вы будете атрибутом, который генерирует предупреждения:

[AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public class IDEMessageAttribute : Attribute
{
    public string Message;

    public IDEMessageAttribute(string message);
}

для этого вам нужно сначала установить Roslyn SDK и запустить новый проект VSIX с анализатором, я опустил некоторые из менее релевантных частей, таких как сообщения, которые вы можете выяснить, как это сделать, в вашем анализаторе ты сделаешь это

public override void Initialize(AnalysisContext context)
{
    context.RegisterSyntaxNodeAction(AnalyzerInvocation, SyntaxKind.InvocationExpression);
}

private static void AnalyzerInvocation(SyntaxNodeAnalysisContext context)
{
    var invocation = (InvocationExpressionSyntax)context.Node;

    var methodDeclaration = (context.SemanticModel.GetSymbolInfo(invocation, context.CancellationToken).Symbol as IMethodSymbol);

    //There are several reason why this may be null e.g invoking a delegate
    if (null == methodDeclaration)
    {
        return;
    }

    var methodAttributes = methodDeclaration.GetAttributes();
    var attributeData = methodAttributes.FirstOrDefault(attr => IsIDEMessageAttribute(context.SemanticModel, attr, typeof(IDEMessageAttribute)));
    if(null == attributeData)
    {
        return;
    }

    var message = GetMessage(attributeData); 
    var diagnostic = Diagnostic.Create(Rule, invocation.GetLocation(), methodDeclaration.Name, message);
    context.ReportDiagnostic(diagnostic);
}

static bool IsIDEMessageAttribute(SemanticModel semanticModel, AttributeData attribute, Type desiredAttributeType)
{
    var desiredTypeNamedSymbol = semanticModel.Compilation.GetTypeByMetadataName(desiredAttributeType.FullName);

    var result = attribute.AttributeClass.Equals(desiredTypeNamedSymbol);
    return result;
}

static string GetMessage(AttributeData attribute)
{
    if (attribute.ConstructorArguments.Length < 1)
    {
        return "This method is obsolete";
    }

    return (attribute.ConstructorArguments[0].Value as string);
}

нет никакого CodeFixProvider для этого вы можете удалить его из решения.

Я лично больше заинтересован в выдаче ошибки, если атрибут будет недействительным, например, параметр был недействительным.