C# · 12月 20, 2021

托管代码分析和代码度量

FxCop是利用规则库来分析托管代码的工具。可以创建任意目的规则——命名约定、安全性、特性使用等。在Visual Studio Team System 2005中,FxCop经过改头换面,成为了托管代码分析(Managed Code Analysis)工具集成在IDE中,这使得分析工作可以通过应用程序的一个简单生成而执行。

首先,创建一个C# Library项目,代码如下:

EntryLevel = Normal = Senior = BONUS = MaximumHours = ComputePayment( (hours > ArgumentOutOfRangeException( (()level * }

尽管这段代码可以编译和运行,但它违背几条代码分析指南中所指定的规则,代码分析工具将帮助我们找到可以改进的地方,改进之后,将变得更加易懂,且会捕获到潜在的运行时错误(如缓冲区溢出)。

默认情况下,对于Visual Studio中的项目而言,代码分析是禁用的,启用代码分析,可以打开项目Properties窗口:

为了在项目生成时启用代码分析,需要选中Enable Code Analysis on Build复选框。从下拉列表框中选择要使用的规则集,保存。

规则集中每个规则都可以设置为下列选项之一:

  Warning(默认):建议修改,但不阻碍项目成功生成  Error: 某些规则或规则组非常重要时,当代码违反,项目将不能生成  Inherit: 意味着该规则和包含它的规则组将使用相同的指示器  None: 表示无设置

根据需要,我们可以做出类似下图的设置:

一旦启用了代码分析并配置了反映开发标准的规则之后,每次生成项目时都会进行代码分析。下图为分析结果显示:

当每次执行代码分析时,其结果都会存储到一个XML文件中,用IE打开XML文件可以看到如下信息

很多代码分析规则与标准的命名约定有关,比如此处有一个警告“CA1707 Identifiers should not contain underscores Remove the underscores from type name ‘PayCalculator.Pay_Level’. SampleLibrary PayCalculator.cs 7”,该规则实施的命名约定规定,类型名不能带下划线,于是可以使用内置重构对其进行重命名。又如警告“CA1810 Initialize reference type static fields inline Initialize all static fields in ‘PayCalculator’ when those fields are declared and remove the explicit static constructor. SampleLibrary PayCalculator.cs 16”,该规则指出,在变量定义时赋值,代码运行效率更高。

规则还有助于保证正确使用框架,如警告“CA2208 Instantiate argument exceptions correctly Method ‘PayCalculator.ComputePayment(int,PayCalculator.Pay_Level)’ passes ‘Employee works too much’ as the ‘paramName’ argument to a ‘ArgumentOutOfRangeException’ constructor. Replace this argument with one of the method’s parameter names. Note that the provided parameter name should have the exact casing as declared on the method. SampleLibrary PayCalculator.cs 23”,该规则检测到我们可能没有正确创建ArgumentOutOfRangeException,要修复该问题,需要修改抛出的异常代码:

(hours > ArgumentOutOfRangeException(, }

在剩余的警告中,有一个十分常见的建议:“CA1014 Mark assemblies with CLSCompliantAttribute Mark ‘SampleLibrary.dll’ with CLSCompliant(true) because it exposes externally visible types. SampleLibrary (Global)”,如果创建的是一个可重用的库程序集,而且可能会被多种.NET语言代码使用,那么就需要考虑解决该问题。解决该问题需要打开AssemblyInfo.cs文件添加:[assembly: System.CLSCompliant(true)]

VS提供了很多规则,但并不是所有规则都适合于每个项目,为了阻止不相关的消息再次出现,可以右击该规则违反项,选择Suppress Message即可。当阻止了某个消息后,VS会自动在代码中添加一个特性,表明不使用该规则。Suppress Message可应用于代码结构,如字段、方法、类或整个程序集。

经过部分警告处理后,代码变成如下:

EntryLevel = Senior = MaximumHours = [System.Diagnostics.CodeAnalysis.SuppressMessage(,,MessageId = BONUS = ComputePayment( (hours > ArgumentOutOfRangeException(, (()level * }

以上即为静态代码分析的执行过程。

对于静态代码分析,也可以使用命令行分析工具,这个工具叫做FxCopCmd.exe,它可以执行VS IDE的所有代码分析功能。实际上,IDE也是通过调用它来进行分析并生成报告的,该文件位于C:\Program Files (x86)\Microsoft Visual Studio 12.0\Team Tools\Static Analysis Tools\FxCop下:

FxCopCmd的常见用法是从生成过程自动进行代码分析。

很多静态分析工具使用源代码检查来发现问题,但对于FxCop而言,Microsoft决定以.NET本身内在的功能为基础来创建规则。最初的FxCop版本将反射作为规则的基础,现在又有了新的选择,内省。内省能够检查目标程序,发现其类型以及与类型相关的详细信息。内省比反射更快,且支持多线程操作。

代码度量工具是一组软件度量集,使用它可以了解开发代码的内部质量。代码度量为确定代码复杂度、发现难以维护的代码区域提供了一种便捷的方法。代码度量信息是在方法一级进行计算的,然后层层向上到程序集一级。Visual Studio 2010可以计算5种代码度量:

  圈复杂度:用于度量代码的结构复杂度,通过计算源代码中的不同代码路径数而得到,包括if语句、循环等。圈复杂度越大,表明代码越复杂,越需要重构。  继承深度:用于度量从类层次的根所派生的类的数量。较深层次的继承会使代码难以理解。  类耦合度:用于度量一个类对其他类的依赖程度。  代码行数:用于度量一个方法的可执行行代码的行数。  可维护性指标:是多个度量的组合值,包括圈复杂度,平均代码行数及计算复杂度:    Max(0,(171 – 5.2* ln(Halstead Volume)-0.23*(Cyslomatic Complexity) – 16.2 * ln(Lines of Code)) *100 / 171)

可维护性指标值在1到100之间。值越大表示代码越容易维护。要想对代码进行代码度量分析,只需要在VS中右击指定的解决方案或项目并选择Calculate Code Metrics即可。比如,我们对刚刚那段SampleLibrary代码进行一次代码度量分析,结果如下: