如果使用特定的枚举值,如何生成警告

Posted

技术标签:

【中文标题】如果使用特定的枚举值,如何生成警告【英文标题】:How to generate a warning if a specific enum value is used 【发布时间】:2013-02-11 19:21:40 【问题描述】:

我正在使用由第 3 方程序集公开的枚举,例如,

public enum APIEnum

  Val1,
  Val2

。但是,其中一些值会导致我的应用程序出现错误行为。如果代码中使用了这些“坏”枚举值之一,我想生成编译器警告,例如,

APIEnum usedVal = APIEnum.Val2;

Compiler Warning: APIEnum.Val2 causes incorrect behavior.

我的最终目标是生成一个警告,如果使用了错误的值(占总案例的 2%),则必须有意识地#pragma'd。否则,会出现警告,并且由于我们将警告视为错误,因此会中断编译,直到修复或 #pragma'd。

我已经查看了线程 here 和 here 使用 Obsolete 属性来解决这个问题,但我担心 Obsolete 会引起混淆,因为该值并没有真正过时。

我已经考虑过使用 Resharper 代码分析插件来解决问题的可能性,这绝对是一种选择。我不是 Resharper 方面的专家,也不是如何通过 Resharper 最好地解决问题的专家。

【问题讨论】:

【参考方案1】:

您可以在 ReSharper 中使用结构搜索。转到ReSharper -> Options | Code Inspection -> Custom patterns,单击Add Pattern,在Search pattern 字段中输入APIEnum.Val2,在Description 中输入您的错误描述。将模式严重性设置为Show as error。点击Add。就这样。唯一的缺点是如果您的项目中有另一个 APIEnum 具有相同的 Val2 值,即使在不同的命名空间中,它也会被标记为错误。

您还应该打开ReSharper -> Options | Code Inspection -> Settings | Analyse errors in whole solution 以显示每个文件中的错误。

【讨论】:

感谢您的想法。在 Resharper 代码检查选项中,是否有一种简单的方法可以将该规则传递给所有开发人员并构建机器? (这里是 Resharper 新手。) 是的,添加模式后,单击选项屏幕上的“保存到”并选择“解决方案...团队共享”。然后将文件 YourSolution.sln.dotSettings 添加到版本控制系统,然后它应该适用于所有人。附言您还应该打开ReSharper -> Options | Code Inspection -> Settings | Analyse errors in whole solution 以显示每个文件中的错误。【参考方案2】:

您可以为此创建自定义代码分析 (FxCop) 规则,或者确实推出您自己的 Resharper 规则。自定义代码分析规则应该比较简单,check out my rule which checks whether a regex compiles or not,它会找到RegexOptions 枚举的所有用途。您应该能够从那里构建自己的自定义规则。

自定义代码分析规则的一般优秀网站:

Introspector Tutorial

如果您在编写自己的规则时遇到困难,请不要犹豫,分享到目前为止的代码以寻求更具体的帮助。

使用 VisitAssignment 语句,然后使用 assignment.Target.Type.FullName 获取底层枚举类型。一定要检查 Target.Type 是否为空,委托可以有一个空类型。

Methodcall 也会看到 Enum:

【讨论】:

我投票这个答案最适合我的问题。虽然我不喜欢执行规则所需的大量代码,但我可以保证静态代码分析会破坏编译步骤(当我在 IDE 中测试该方法时,我发现 Resharper 结果最终成为一个可忽略的麻烦)。 【参考方案3】:

我已经使用 FxCop 方法制作了一个解决方案原型,但我认为 FxCop 无法真正解决它。我在规则中尝试了以下代码:

public class DoNotUseSpecificEnum : RuleBase

  private string[] _enumValsToCheck =
  
    "APIEnum.Val2"
  ;

  public DoNotUseSpecificEnum ()
    : base("DoNotUseSpecificEnum ")  

  public override void VisitBinaryExpression(BinaryExpression binaryExpression)
  
    if ( _enumValsToCheck.Contains(
      binaryExpression.Operand1.ToString()) 
      || _enumValsToCheck.Contains( binaryExpression.Operand2.ToString() ) )
    
      this.Problems.Add(new Problem(base.GetResolution(),
        binaryExpression.SourceContext));
    

    base.VisitBinaryExpression(binaryExpression);
  

当我跟踪到 VisitBinaryExpression 时,我发现 Operand1 的值是“1”而不是“APIEnum.Val2”。事后看来,这是有道理的(FxCop 在 MSIL 上工作,它用数字文字替换了枚举名称/值);我只是希望在深入了解自定义 FxCop 规则的痛苦/荣耀之前就已经意识到这一点。 :)

我发现的另一种方法是使用 StyleCop 进行语法分析,但这看起来比自定义 FxCop 规则更难弄清楚并且不太受欢迎。

我将建议使用 Resharper 团队特定的自定义模式作为管理方式。我仍然担心这种方法(特别是因为我们将在多个解决方案和团队中拥有相同的规则),但构建机器的关注比我想象的要小得多。 TeamCity 允许 build-time inspection of Resharper rules 开箱即用,因此我们至少可以配置我们的 CI 服务器以查找和报告未使用 Resharper 语法抑制的枚举的使用。

【讨论】:

传奇仍在继续 - 似乎没有任何方法可以抑制由单个实例的自定义模式生成的 Resharper 警告或错误。 (// ReSharper disable 不适用于自定义模式。)我找到了一种使用#region RFail here 的有前途的方法,但是没有太多示例,并且在我尝试时它不起作用。我回到绘图板...... 当您查看 AssignmentExpressions 时,您也将获得 Enum 的基本类型,然后您可以检查 int 的值与您的 enum 的预期值。 感谢您的帮助,jessehouwing。在逐步浏览原型 VisitAssignmentStatement 时,我无法区分 APIEnum 和 AnyOtherEnum。我看到 assignment.Target.Type.BaseType.FullName 是“System.Enum”,但我在 assignment.Target 字段的任何地方都找不到名称或对 APIEnum 类型的引用。 (我可能会错过它 - assignment.Target 是一个复杂的对象!)但是如果没有字符串 APIEnum 出现在某处,我无法将目标枚举类型与任何其他枚举类型隔离开来...... 用更多细节更新了我的原始答案,我想你快到了:)。 酷 - 肯定越来越近了。 VisitAssignment 在我的原型中融合在一起。我也开始调查 VisitBinaryExpression。我发现我可以通过 ((BinaryExpression)binaryExpression.Operand1).Operand1.Type.FullName 以一种复杂的方式获取枚举变量的原始类型。我必须小心演员的安全,但我可以得到枚举的真实姓名。到达那里!

以上是关于如果使用特定的枚举值,如何生成警告的主要内容,如果未能解决你的问题,请参考以下文章

在 GCC 中使用不同枚举类型分配或执行算术时如何发出警告?

获取值类型标签的父枚举

将枚举值保存到字典中

将枚举转换为具有溢出的整数时会出现警告

如何使用jQuery从数组中删除特定值

如何在python中使用生成器查找特定值