如何降低此 c# 方法的圈复杂度?
How to reduce cyclomatic complexity on this c# method?
我目前正在为我的 c# 类 做一个项目。我们的老师给了我们一些我们必须遵守的代码度量限制,其中之一就是圈复杂度。现在他下面方法的复杂度是5,但它需要是4。有什么办法可以改善吗?
我说的方法:
private bool MethodName()
{
int counter = 0;
for (int k = 0; k < 8; k++)
{
for (int j = 0; j < 3; j++)
{
if (class1.GetBoard()[array1[k, j, 0], array1[k, j, 1]] == player.WhichPlayer()) counter++;
}
if (counter == 3) return true;
else counter = 0;
}
return false;
}
我可以包装条件来减少它。例如
private bool MethodName()
{
for (int k = 0; k < 8; k++)
{
bool b = true;
for (int j = 0; j < 3; j++)
{
b &= class1.GetBoard()[array1[k, j, 0], array1[k, j, 1]] == player.WhichPlayer();
}
if (b) return true;
}
return false;
}
对于 OP(似乎才刚刚开始编程):
很高兴您得到了一项任务来降低方法的圈复杂度,并且了解它是什么以及如何将其作为一般做法保持较低水平是很好的。
但是,尽量不要对这些指标过于热心。让代码 尽可能简单 更有价值,易于推理和快速理解,并且只在分析应用程序并了解最重要的地方后才担心指标。
对于更有经验的程序员:
这个简单的问题让我想起了一个very famous discussion from 1968 between Dijkstra and other fellas on the ACM periodic. Although I tend to align with him on this matter, that was one answer from Frank Rubin很有道理的
Frank 基本上提倡“优雅”可以多次来自代码清晰度,而不是任何其他实践指标。那时,讨论的是对当时流行语言的过度使用 goto 声明。今天,讨论围绕着圈复杂度、简洁性、面向对象等等。
在我看来,底线是:
- 了解你的工具
- 代码清晰
- 尝试在第一遍就编写高效的代码,但不要想太多
- 剖析您的代码并决定在哪些工作上花费更多时间
回到问题
问题中的实现在我的 Visual Studio 分析器中获得了以下分数:
Cycl. Compl: 5; Maintainability: 67
@Boris 提供的片段得到了这个:
Cycl. Compl: 4; Maintainability: 68
虽然圈复杂度有所提高,但可维护性指标基本保持不变。就我个人而言,大多数时候我认为后一种指标更有价值。
只是为了好玩,让我们看看使用可怕的 goto
语句的类似于 Frank Rubin 提出的解决方案看起来像:
private bool MethodName() {
for (int k = 0; k < 8; k++) {
for (int j = 0; j < 3; j++) {
if (watheverTestCondition(k, j) is false) goto reject;
}
// condition is true for all items in this row
return true;
// if condition is false for any item, go straight to this line
reject:;
}
return false;
}
老实说,我认为这是最清晰、最简单和最有效的实现。我一般推荐 goto
作为代码功能吗? 否。在这种特定情况下,它是否完美顺畅地适合? 是。那么指标呢?
Cycl. Compl: 4; Maintainability: 70
奖金
只是因为如果我不说的话我就睡不着,这就是你在现实生活中如何实现这个:
obj.Any(row => row.All(watheverTestCondition));
Cycl. Compl: 1; Maintainability: 80
我目前正在为我的 c# 类 做一个项目。我们的老师给了我们一些我们必须遵守的代码度量限制,其中之一就是圈复杂度。现在他下面方法的复杂度是5,但它需要是4。有什么办法可以改善吗?
我说的方法:
private bool MethodName()
{
int counter = 0;
for (int k = 0; k < 8; k++)
{
for (int j = 0; j < 3; j++)
{
if (class1.GetBoard()[array1[k, j, 0], array1[k, j, 1]] == player.WhichPlayer()) counter++;
}
if (counter == 3) return true;
else counter = 0;
}
return false;
}
我可以包装条件来减少它。例如
private bool MethodName()
{
for (int k = 0; k < 8; k++)
{
bool b = true;
for (int j = 0; j < 3; j++)
{
b &= class1.GetBoard()[array1[k, j, 0], array1[k, j, 1]] == player.WhichPlayer();
}
if (b) return true;
}
return false;
}
对于 OP(似乎才刚刚开始编程):
很高兴您得到了一项任务来降低方法的圈复杂度,并且了解它是什么以及如何将其作为一般做法保持较低水平是很好的。
但是,尽量不要对这些指标过于热心。让代码 尽可能简单 更有价值,易于推理和快速理解,并且只在分析应用程序并了解最重要的地方后才担心指标。
对于更有经验的程序员:
这个简单的问题让我想起了一个very famous discussion from 1968 between Dijkstra and other fellas on the ACM periodic. Although I tend to align with him on this matter, that was one answer from Frank Rubin很有道理的
Frank 基本上提倡“优雅”可以多次来自代码清晰度,而不是任何其他实践指标。那时,讨论的是对当时流行语言的过度使用 goto 声明。今天,讨论围绕着圈复杂度、简洁性、面向对象等等。
在我看来,底线是:
- 了解你的工具
- 代码清晰
- 尝试在第一遍就编写高效的代码,但不要想太多
- 剖析您的代码并决定在哪些工作上花费更多时间
回到问题
问题中的实现在我的 Visual Studio 分析器中获得了以下分数:
Cycl. Compl: 5; Maintainability: 67
@Boris 提供的片段得到了这个:
Cycl. Compl: 4; Maintainability: 68
虽然圈复杂度有所提高,但可维护性指标基本保持不变。就我个人而言,大多数时候我认为后一种指标更有价值。
只是为了好玩,让我们看看使用可怕的 goto
语句的类似于 Frank Rubin 提出的解决方案看起来像:
private bool MethodName() {
for (int k = 0; k < 8; k++) {
for (int j = 0; j < 3; j++) {
if (watheverTestCondition(k, j) is false) goto reject;
}
// condition is true for all items in this row
return true;
// if condition is false for any item, go straight to this line
reject:;
}
return false;
}
老实说,我认为这是最清晰、最简单和最有效的实现。我一般推荐 goto
作为代码功能吗? 否。在这种特定情况下,它是否完美顺畅地适合? 是。那么指标呢?
Cycl. Compl: 4; Maintainability: 70
奖金
只是因为如果我不说的话我就睡不着,这就是你在现实生活中如何实现这个:
obj.Any(row => row.All(watheverTestCondition));
Cycl. Compl: 1; Maintainability: 80