降低 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

查看您的代码,您可以提取一些方法,我做了一些重构以降低复杂性,如下面的列表所示:

  1. 将主体代码提取到方法中
  2. 将“记录类型”正文代码提取到另一种方法
  3. 您仍然可以重构为 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,如 HeaderReaderBodyReaderDetailReader,但这可能是一个过度工程,因此您将决定是否值得。

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 方法。