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

При использовании 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.


person Micah    schedule 30.09.2008    source источник
comment
Это C #? Я собираюсь предположительно пометить это как C # (не C), исходя из предположения, что исходный плакат хотел выбрать именно это.   -  person Onorio Catenacci    schedule 30.09.2008
comment
это vb, я думаю, определенно не c #   -  person Sklivvz    schedule 30.09.2008
comment
Это недопустимый VB или C # ... так что это ...?!   -  person ljs    schedule 30.09.2008
comment
Я только пометил его как C #, потому что он изначально пометил его как C. Может быть, он говорит об управляемом C ++? Если исходный постер читает этот комментарий, пожалуйста, поясните вопрос.   -  person Onorio Catenacci    schedule 30.09.2008
comment
Он должен быть помечен как C # или VB.Net, поэтому я пометил их обоими тегами. Я могу делать и то, и другое, поэтому мне все равно. Возможно, он не должен быть помечен ни одним из них.   -  person Micah    schedule 30.09.2008
comment
Я не хотел быть несправедливым по этому поводу, удалил теги, так как опасался, что это может ввести людей в заблуждение относительно образца кода в q ... но, очевидно, если вы определенно думаете, что они должны быть там, это круто. все еще немного запутался в том, чтобы пометить его vs2008 ...: -S ??!   -  person ljs    schedule 30.09.2008
comment
Я полагаю, C # и vb.net можно было бы удалить, но он помечен как vs2008, потому что я думаю, что это что-то напрямую связано с vs2008 и компилятором   -  person Micah    schedule 30.09.2008
comment
Я добавил несколько примеров кода и изображение того, что вы хотели! удачи чувак!   -  person Pablo Fernandez    schedule 01.10.2008
comment
Старый вопрос, но теперь вы можете определить пользовательские предупреждения компилятора с помощью Roslyn.   -  person RJ Cuthbertson    schedule 22.01.2015
comment
@RJCuthbertson Как вы можете сделать это с Roslyn?   -  person jrummell    schedule 02.03.2016
comment
@jrummell Говоря Roslyn, анализаторы кода: johnkoerner.com/csharp/creating- ваш-первый-анализатор кода   -  person RJ Cuthbertson    schedule 02.03.2016
comment
@RJCuthbertson Я переместил ваш комментарий в принятый ответ, чтобы уделить ему должное внимание.   -  person jpaugh    schedule 23.06.2017


Ответы (10)


Обновлять

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


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

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

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

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

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

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

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

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

person ljs    schedule 30.09.2008
comment
Я ищу то же самое. Устаревшее «работает», но код на самом деле не столько устаревший, сколько неполный из-за рефакторинга. - person g .; 09.07.2009
comment
Я согласен с @g и, вероятно, с первоначальным автором. Устаревшее означает устаревшее, не используйте. Я хочу отметить что-то, что это компилируется, но нам действительно нужно либо а) завершить функциональность, или б) провести рефакторинг. Это было бы скорее атрибутом времени разработки. Также работают задачи, например // TODO :, но я не использую их, как я предполагаю, многие люди не используют, но регулярно просматриваю предупреждения компилятора. - person MikeJansen; 12.09.2012
comment
Еще одна причина не использовать тег [Obsolete] заключается в том, что это может вызвать проблемы, если вам нужно выполнить XmlSerialization со свойством. Добавление тега [Obsolete] также добавляет атрибут [XmlIgnore] за кулисами. - person burnttoast11; 15.09.2012
comment
Устаревшее другое. Устаревший выдает предупреждение о каждой строке кода, вызывающей этот метод. Я не думаю, что это то, чего хочет плакат (по крайней мере, это не то, что я хотел, когда поискал и нашел этот вопрос). Я думал, что вопрос искал предупреждение, которое должно появиться в определении функции, а не в том месте, где оно используется. - person Nick; 17.09.2012
comment
Не лучший ответ. -1 за то, что считает, что ваша неспособность придумать причину, по которой не использовать его, заслуживает критики. Такое отношение не поощряет подлинность. - person Mike Socha III; 26.03.2016
comment
@Nick Я думаю, они хотят, чтобы это отображалось, если функция вызывается. Это тоже мой вариант использования. Хотите иметь возможность пометить функцию как вызываемую только из тестового кода или не компилируемую в подобных продуктах. - person Jesse Pepper; 19.12.2018
comment
Вот пример самого исходного кода ядра .net, который является неправильным использованием ObsoleteAttribute, указывающим на то, что должны быть другие виды или способы создания вашего собственного. [System.ComponentModel.EditorBrowsableAttribute((System.ComponentModel.EditorBrowsableState)(1))] [System.ObsoleteAttribute("This API supports the .NET Framework infrastructure and is not intended to be used directly from your code.")] - person Jesse Pepper; 19.12.2018

Стоит попробовать.

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

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

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

ОБНОВЛЕНИЕ: с помощью этого кода выдается предупреждение (не очень хорошо, но я не думаю, что есть что-нибудь получше).

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
{

}
person Pablo Fernandez    schedule 30.09.2008
comment
Вы можете вставить то, что он генерирует? Мне любопытно. - person Micah; 30.09.2008
comment
Предупреждение компиляции запускается, даже если свойство / метод не вызывается. - person Rolf Kristensen; 20.09.2010
comment
Здесь хорошие предложения. Я хотел сделать то же самое и в итоге просто выбросил NotImplementedExceptions. Не лучшее решение, поскольку они не отображаются во время компиляции, только во время выполнения, если код выполняется. Я сам попробую. - person MonkeyWrench; 02.03.2011
comment
Было бы здорово, если бы ObsolteAttribute мог поддерживать такие выражения, как DebuggerDisplayAttribute, тогда мы действительно могли бы делать кое-что классное. visualstudio.uservoice.com / форумы / 121579-visual-studio / - person jpierson; 24.05.2013
comment
Если вы реализуете IDisposable в этих устаревших классах, это означает, что вы можете заключить свой хитроумный тестовый код в блок using. Как это: using(new MustRefactor()){DodgyCode();}. После этого вы сможете найти все способы использования. Я использую это прямо сейчас, чтобы Sleep поток внутри цикла for мне нужно искусственно замедлить в целях отладки. - person Iain Fraser; 30.10.2014
comment
Если кому-то было интересно, как это сделать с помощью настраиваемого атрибута, я предоставил ответ ниже - person johnny 5; 31.07.2017

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

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

В компиляторах Microsoft вы обычно можете использовать прагму message:

#pragma message ( "text" )

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

person Douglas Mayle    schedule 30.09.2008
comment
#warning или #pragma - это директивы препроцессора, поэтому они будут выполняться независимо от наличия кода бывших коллег Мики и вообще не взаимодействуют с атрибутом. Совершенно очевидно, что устаревшее - единственное средство для достижения этой цели ... - person ljs; 30.09.2008
comment
Это не отвечает на вопрос. - person cskwg; 24.08.2020

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

public void DoEverything() {
   #warning "This code sucks"
}
person Ted Elliott    schedule 30.09.2008

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

[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
{
    // .....
}

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

Namespace.MappingToDo устарел: «Mapping ToDo».

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

person Tomasz Modelski    schedule 10.01.2010

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

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

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

Al

person user4089256    schedule 28.09.2014
comment
я считаю это более предпочтительным решением - person Samuel; 27.02.2016
comment
что, если вы хотите пометить функцию как не вызываемую в производственном коде или аналогичную. Итак, вы хотите, чтобы он запускался, если функция или класс вызывается или создается, но не если он просто скомпилирован. - person Jesse Pepper; 19.12.2018

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

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

person technophile    schedule 30.09.2008

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

person bdukes    schedule 30.09.2008

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

person bubi    schedule 12.11.2014

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

Я создал атрибут Type Called 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, вы можете удалить его из решения.

person johnny 5    schedule 31.07.2017