自定义编译器警告

时间:2020-03-06 14:56:09  来源:igfitidea点击:

在.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

我希望它生成一个编译器警告,指出"此代码为sux,应予以注意"。我知道如何创建自定义属性,问题是如何使它在Visual Studio中生成编译器警告。

解决方案

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

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

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

#pragma message ( "text" )

我们提到了.Net,但未指定是使用C / C ++还是C#进行编程。如果我们使用C#编程,那么我们应该知道C支持#warning格式。

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

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

不知道这是否行得通,但是值得一试。

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

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

然后,当我们使用" MustRefactor"属性标记方法时,可能会显示编译警告。

我说"也许"和"可能"是因为我没有尝试过。请告诉我它是否无效,所以我将删除答案。

问候!

更新:已测试。它会生成一个编译时警告,但错误消息看起来很有趣,我们应该自己查看并选择。这非常接近我们想要实现的目标。

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

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
{

}

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

更新

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

我不相信这是可能的。 ObsoleteAttribute由编译器专门处理,并在Cstandard中定义。为什么地球上的ObsoleteAttribute不可接受?在我看来,这恰恰是它的设计目标,并且可以满足要求!

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

并不是要变得无益,只是想知道为什么我们不热衷于使用它。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

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

从标准:

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.

那不是总结需求吗?...我们做得不会比我想不到的要好。

我们目前处于大量重构的中间,无法立即修复所有问题。我们只需要使用#warning preproc命令,就需要返回查看代码。它显示在编译器输出中。我认为我们不能将其放在方法上,但可以将其放在方法内部,而且仍然很容易找到。

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

在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 is obsolete:
  'Mapping ToDo'.

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