降低 Class 复杂性 - 认知复杂性 C#
Reduce Class Complexity - Cognitive Complexity C#
如何提高代码中的认知复杂度?
我有一个方法,它有 while 循环,里面有很多 IF ELSE 块,我尝试用 SWITCH 语句删除 IF ELSE,但根据 SONAR 多维数据集分析,认知复杂性没有改善。
这是我现有的代码:
while (this.moveNextDelegate(fileLineEnumerator))
{
var line = fileLineEnumerator.Current;
var recordType = GetRecordType(line); // This Method returns the type of record
if (recordType == "1")
{
headerId++;
fileHeader = line; // Here fileHeader is being used in downsteam code flow - line 19
// some custom logic - deleted
}
else if (recordType == "5")
{
batchHeader = line; // Here batchHeader is being used in downsteam code flow - line 19
isRepeativeRecord = false;
}
else if (recordType == "6")
{
batchHeaderId = // some custom logic - deleted
// Here batchHeaderId is being used in downsteam code flow - line 35
detailId++;
isFlag = false;
isRepeativeRecord = true;
// some custom logic - deleted
}
else if (recordType == "7" && !isFlag)
{
addendaId++;
detailRecordsExist = true;
// some custom logic - deleted
}
currentIndex++;
}
我的新代码使用 Switch 语句 - 但复杂度仍然没有改善
while (this.moveNextDelegate(fileLineEnumerator))
{
var line = fileLineEnumerator.Current;
var recordType = GetRecordType(line);
switch (recordType)
{
case "1":
{
headerId++;
fileHeader = line;
// some custom logic - deleted
break;
}
case "2":
{
batchHeader = line;
isRepeativeRecord = false;
break;
}
case "6":
{
// some custom logic - deleted
break;
}
case "7":
{
if (!isFlag)
{
// some custom logic - deleted
}
break;
}
case "8":
{
if (!isFlag)
{
// some custom logic - deleted
}
break;
}
}
currentIndex++;
}
从 if/else
切换到 switch
语句可能是个好主意,不要从最终代码中丢弃它,但不会降低复杂性,因为“if/else/switch”语句仍然与其他 if
语句一起存在于正文中。
为了避免声纳的复杂性,多写一些简单的方法,每个方法都有一个单一的目标,这样可以更好地测试并减少逻辑了解一下。
https://en.wikipedia.org/wiki/SOLID
查看您的代码,您可以提取一些方法,我做了一些重构以降低复杂性,如下面的列表所示:
- 将主体代码提取到方法中
- 将“记录类型”正文代码提取到另一种方法
- 您仍然可以重构为 classes(谨慎,可能是过度工程)
private void Foo()
{
FileEnumerator fileLineEnumerator = new FileEnumerator();
while (this.moveNextDelegate(fileLineEnumerator))
{
string line = fileLineEnumerator.Current;
ReadNextLine(line);
currentIndex++;
}
}
private void ReadNextLine(string line)
{
var recordType = GetRecordType(line);
if (recordType == "1")
{
this.ReadHeader(line);
}
else if (recordType == "5")
{
ReadBatchHeader(line);
}
else if (recordType == "6")
{
ReadRepeativeRecord();
}
else if (recordType == "7" && !this.isFlag)
{
ReadDetail();
}
}
private void ReadDetail()
{
this.addendaId++;
this.detailRecordsExist = true;
}
private void ReadRepeativeRecord()
{
this.batchHeaderId = this.detailId++;
this.isFlag = false;
this.isRepeativeRecord = true;
}
private void ReadBatchHeader(string line)
{
this.batchHeader = line;
this.isRepeativeRecord = false;
}
private void ReadHeader(string line)
{
this.headerId++;
this.fileHeader = line;
}
看起来你正在写一个 reader,所以如果你有很多 readers/steps 比如阅读文件的页眉、正文、页脚,以及详细信息和递归内容,你可以将每个片段分开一个单独的 class,如 HeaderReader
、BodyReader
、DetailReader
,但这可能是一个过度工程,因此您将决定是否值得。
public class ReadState
{
public RecordType RecordType { get; set; }
public string Line { get; set; }
}
public class ReadResult
{
public int HeaderId { get; set; }
}
public class BodyReader : IYourCustomFileFragmentReaderInterface
{
public bool Test(ReadState state)
{
// check if is header
return state.RecordType == RecordType.Body;
}
public ReadResult Read(ReadResult result, ReadState state)
{
// write state
result.HeaderId = int.Parse(state.Line);
return result;
}
}
使用单独的 reader,您可以在 IYourCustomFileFragmentReaderInterface
列表中分组,调用 Test()
,如果为真,则调用 Read
方法。
如何提高代码中的认知复杂度?
我有一个方法,它有 while 循环,里面有很多 IF ELSE 块,我尝试用 SWITCH 语句删除 IF ELSE,但根据 SONAR 多维数据集分析,认知复杂性没有改善。
这是我现有的代码:
while (this.moveNextDelegate(fileLineEnumerator))
{
var line = fileLineEnumerator.Current;
var recordType = GetRecordType(line); // This Method returns the type of record
if (recordType == "1")
{
headerId++;
fileHeader = line; // Here fileHeader is being used in downsteam code flow - line 19
// some custom logic - deleted
}
else if (recordType == "5")
{
batchHeader = line; // Here batchHeader is being used in downsteam code flow - line 19
isRepeativeRecord = false;
}
else if (recordType == "6")
{
batchHeaderId = // some custom logic - deleted
// Here batchHeaderId is being used in downsteam code flow - line 35
detailId++;
isFlag = false;
isRepeativeRecord = true;
// some custom logic - deleted
}
else if (recordType == "7" && !isFlag)
{
addendaId++;
detailRecordsExist = true;
// some custom logic - deleted
}
currentIndex++;
}
我的新代码使用 Switch 语句 - 但复杂度仍然没有改善
while (this.moveNextDelegate(fileLineEnumerator))
{
var line = fileLineEnumerator.Current;
var recordType = GetRecordType(line);
switch (recordType)
{
case "1":
{
headerId++;
fileHeader = line;
// some custom logic - deleted
break;
}
case "2":
{
batchHeader = line;
isRepeativeRecord = false;
break;
}
case "6":
{
// some custom logic - deleted
break;
}
case "7":
{
if (!isFlag)
{
// some custom logic - deleted
}
break;
}
case "8":
{
if (!isFlag)
{
// some custom logic - deleted
}
break;
}
}
currentIndex++;
}
从 if/else
切换到 switch
语句可能是个好主意,不要从最终代码中丢弃它,但不会降低复杂性,因为“if/else/switch”语句仍然与其他 if
语句一起存在于正文中。
为了避免声纳的复杂性,多写一些简单的方法,每个方法都有一个单一的目标,这样可以更好地测试并减少逻辑了解一下。
https://en.wikipedia.org/wiki/SOLID
查看您的代码,您可以提取一些方法,我做了一些重构以降低复杂性,如下面的列表所示:
- 将主体代码提取到方法中
- 将“记录类型”正文代码提取到另一种方法
- 您仍然可以重构为 classes(谨慎,可能是过度工程)
private void Foo()
{
FileEnumerator fileLineEnumerator = new FileEnumerator();
while (this.moveNextDelegate(fileLineEnumerator))
{
string line = fileLineEnumerator.Current;
ReadNextLine(line);
currentIndex++;
}
}
private void ReadNextLine(string line)
{
var recordType = GetRecordType(line);
if (recordType == "1")
{
this.ReadHeader(line);
}
else if (recordType == "5")
{
ReadBatchHeader(line);
}
else if (recordType == "6")
{
ReadRepeativeRecord();
}
else if (recordType == "7" && !this.isFlag)
{
ReadDetail();
}
}
private void ReadDetail()
{
this.addendaId++;
this.detailRecordsExist = true;
}
private void ReadRepeativeRecord()
{
this.batchHeaderId = this.detailId++;
this.isFlag = false;
this.isRepeativeRecord = true;
}
private void ReadBatchHeader(string line)
{
this.batchHeader = line;
this.isRepeativeRecord = false;
}
private void ReadHeader(string line)
{
this.headerId++;
this.fileHeader = line;
}
看起来你正在写一个 reader,所以如果你有很多 readers/steps 比如阅读文件的页眉、正文、页脚,以及详细信息和递归内容,你可以将每个片段分开一个单独的 class,如 HeaderReader
、BodyReader
、DetailReader
,但这可能是一个过度工程,因此您将决定是否值得。
public class ReadState
{
public RecordType RecordType { get; set; }
public string Line { get; set; }
}
public class ReadResult
{
public int HeaderId { get; set; }
}
public class BodyReader : IYourCustomFileFragmentReaderInterface
{
public bool Test(ReadState state)
{
// check if is header
return state.RecordType == RecordType.Body;
}
public ReadResult Read(ReadResult result, ReadState state)
{
// write state
result.HeaderId = int.Parse(state.Line);
return result;
}
}
使用单独的 reader,您可以在 IYourCustomFileFragmentReaderInterface
列表中分组,调用 Test()
,如果为真,则调用 Read
方法。