C# 自定义编译器警告

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/154109/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 15:55:00  来源:igfitidea点击:

Custom Compiler Warnings

提问by Micah

When using the ObsoleteAtribute in .Net it gives you compiler warnings telling you that the object/method/property is obsolete and somthing else should be used. I'm currently working on a project that requires a lot of refactoring an ex-employees code. I want to write a custom attribute that I can use to mark methods or properties that will generate compiler warnings that give messages that I write. Something like this

当在 .Net 中使用 ObsoleteAtribute 时,它​​会给你编译器警告,告诉你对象/方法/属性已经过时,应该使用其他东西。我目前正在从事一个需要大量重构前雇员代码的项目。我想编写一个自定义属性,我可以用它来标记方法或属性,这些方法或属性将生成编译器警告,提供我编写的消息。像这样的东西

[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

I want this to generate a compiler warning that says, "This code sux and should be looked at". I know how to create a custom attribute, the question is how do I cause it to generate compiler warnings in visual studio.

我希望这会生成一个编译器警告,上面写着“此代码 sux 并且应该查看”。我知道如何创建自定义属性,问题是如何让它在 Visual Studio 中生成编译器警告。

采纳答案by ljs

Update

更新

This is now possible with Roslyn (Visual Studio 2015). You can builda code analyzerto check for a custom attribute

Roslyn (Visual Studio 2015) 现在可以做到这一点。你可以建立一个代码分析器来检查自定义属性



I don't believe it's possible. ObsoleteAttribute is treated specially by the compiler and is defined in the C# standard. Why on earth is ObsoleteAttribute not acceptable? It seems to me like this is precisely the situation it was designed for, and achieves precisely what you require!

我不相信这是可能的。ObsoleteAttribute 由编译器特别处理,并在 C# 标准中定义。为什么 ObsoleteAttribute 是不可接受的?在我看来,这正是它的设计目的,并且正是您所需要的!

Also note that Visual Studio picks up the warnings generated by ObsoleteAttribute on the fly too, which is very useful.

另请注意,Visual Studio 也会即时获取 ObsoleteAttribute 生成的警告,这非常有用。

Don't mean to be unhelpful, just wondering why you're not keen on using it...

不要故意无用,只是想知道为什么你不热衷于使用它......

Unfortunately ObsoleteAttribute is sealed (probably partly due to the special treatment) hence you can't subclass your own attribute from it.

不幸的是 ObsoleteAttribute 是密封的(可能部分是由于特殊处理)因此您不能从中继承您自己的属性。

From the C# standard:-

来自 C# 标准:-

The attribute Obsolete is used to mark types and members of types that should no longer be used.

If a program uses a type or member that is decorated with the Obsolete attribute, the compiler issues a warning or an error. Specifically, the compiler issues a warning if no error parameter is provided, or if the error parameter is provided and has the value false. The compiler issues an error if the error parameter is specified and has the value true.

属性 Obsolete 用于标记不应再使用的类型和类型的成员。

如果程序使用用 Obsolete 属性修饰的类型或成员,编译器会发出警告或错误。具体来说,如果没有提供错误参数,或者提供了错误参数并且值为 false,编译器会发出警告。如果指定了 error 参数并且值为 true,则编译器会发出错误。

Doesn't that sum up your needs?... you're not going to do better than that I don't think.

这不是总结了您的需求吗?...您不会做得比我认为的更好。

回答by Douglas Mayle

In some compilers you can use #warning to issue a warning:

在某些编译器中,您可以使用 #warning 发出警告:

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

In Microsoft compilers, you can typically use the message pragma:

在 Microsoft 编译器中,您通常可以使用消息编译指示:

#pragma message ( "text" )

You mentioned .Net, but didn't specify whether you were programming with C/C++ or C#. If you're programming in C#, than you should know that C# supports the #warning format.

您提到了 .Net,但没有说明您是使用 C/C++ 还是 C# 进行编程。如果您使用 C# 进行编程,那么您应该知道C# 支持 #warning 格式

回答by technophile

I don't think you can. As far as I know support for ObsoleteAttribute is essentially hardcoded into the C# compiler; you can't do anything similar directly.

我不认为你可以。据我所知,对 ObsoleteAttribute 的支持本质上是硬编码到 C# 编译器中的;你不能直接做任何类似的事情。

What you might be able to do is use an MSBuild task (or a post-build event) that executes a custom tool against the just-compiled assembly. The custom tool would reflect over all types/methods in the assembly and consume your custom attribute, at which point it could print to System.Console's default or error TextWriters.

您可能能够做的是使用 MSBuild 任务(或构建后事件),该任务针对刚刚编译的程序集执行自定义工具。自定义工具将反映程序集中的所有类型/方法并使用您的自定义属性,此时它可以打印到 System.Console 的默认或错误 TextWriters。

回答by Pablo Fernandez

This is worth a try.

这值得一试。

You can't extend Obsolete, because it's final, but maybe you can create your own attribute, and mark that class as obsolete like this:

您不能扩展 Obsolete,因为它是最终的,但也许您可以创建自己的属性,并将该类标记为过时,如下所示:

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

Then when you mark your methods with the "MustRefactor" attribute, the compile warnings will show. It generates a compile time warning, but the error message looks funny, you should see it for yourself and choose. This is very close to what you wanted to achieve.

然后,当您使用“MustRefactor”属性标记您的方法时,将显示编译警告。它会生成编译时警告,但错误消息看起来很有趣,您应该自己查看并选择。这非常接近您想要实现的目标。

UPDATE: With this codeIt generates a warning (not very nice, but I don't think there's something better).

更新:使用此代码它会生成一个警告(不是很好,但我认为没有更好的东西)。

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
{

}

回答by bdukes

Looking at the source for ObsoleteAttribute, it doesn't look like it's doing anything special to generate a compiler warning, so I would tend to go with @technophileand say that it is hard-coded into the compiler. Is there a reason you don't want to just use ObsoleteAttributeto generate your warning messages?

查看ObsoleteAttribute的源代码,它看起来并没有做任何特殊的事情来生成编译器警告,所以我倾向于使用 @ technophile并说它是硬编码到编译器中的。您是否有理由不想只使用ObsoleteAttribute来生成警告消息?

回答by Ted Elliott

We're currently in the middle of a lot of refactoring where we couldn't fix everything right away. We just use the #warning preproc command where we need to go back and look at code. It shows up in the compiler output. I don't think you can put it on a method, but you could put it just inside the method, and it's still easy to find.

我们目前正在进行大量重构,无法立即修复所有问题。我们只需在需要返回查看代码的地方使用 #warning preproc 命令。它显示在编译器输出中。我不认为你可以把它放在一个方法上,但是你可以把它放在方法里面,它仍然很容易找到。

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

回答by Tomasz Modelski

In VS 2008 (+sp1) #warnings don't show properly in Error List after Clean Soultion & Rebuild Solution, no all of them. Some Warnings are showed in the Error List only after I open particular class file. So I was forced to use custom attribute:

在 VS 2008 (+sp1) 中,#warnings 在 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()
    {}
}

So when I flag some code with it

所以当我用它标记一些代码时

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

It produces warnings like this:

它会产生如下警告:

Namespace.MappingToDo is obsolete: 'Mapping ToDo'.

Namespace.MappingToDo 已过时:'Mapping ToDo'。

I can't change the text of the warning, 'Some comment' is not showed it Error List. But it will jump to proper place in file. So if you need to vary such warning messages, create various attributes.

我无法更改警告的文本​​,“某些评论”未显示错误列表。但它会跳转到文件中的适当位置。因此,如果您需要更改此类警告消息,请创建各种属性。

回答by user4089256

What you are trying to do is a misuse of attributes. Instead use the Visual Studio Task List. You can enter a comment in your code like this:

您试图做的是滥用属性。而是使用 Visual Studio 任务列表。您可以像这样在代码中输入注释:

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

Then open View / Task List from the menu. The task list has two categories, user tasks and Comments. Switch to Comments and you will see all of your //Todo:'s there. Double clicking on a TODO will jump to the comment in your code.

然后从菜单中打开查看/任务列表。任务列表有两个类别,用户任务和评论。切换到评论,您将看到所有的 //Todo: 都在那里。双击 TODO 将跳转到代码中的注释。

Al

回答by bubi

There are several comments that suggest to insert warnings or pragma. Obsolete works in a very different way! Marking obsolete a function of a library L, the obsolete message raises when a program calls the function even if the caller program is not in the library L. Warning raises the message ONLY when L is compiled.

有几条评论建议插入警告或编译指示。过时的工作方式非常不同!将库 L 的函数标记为过时,即使调用程序不在库 L 中,程序调用该函数时也会引发过时消息。警告仅在编译 L 时引发消息。

回答by johnny 5

Here is the Roslyn Implementation, so you can create your own attributes that give warnings or errors on the fly.

这是 Roslyn 实现,因此您可以创建自己的属性,即时给出警告或错误。

I've create an attribute Type Called IdeMessagewhich will be the attribute which generates warnings:

我创建了一个属性 Type CalledIdeMessage这将是生成警告的属性:

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

    public IDEMessageAttribute(string message);
}

In order to do this you need to install the Roslyn SDK first and start a new VSIX project with analyzer. I've omitted some of the less relevant piece like the messages, you can figure out how to do that. In your analyzer you do this

为此,您需要先安装 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);
}

There are no CodeFixProvider for this you can remove it from the solution.

没有为此的 CodeFixProvider,您可以将其从解决方案中删除。