【问题标题】:Reduce Class Complexity - Cognitive Complexity C#降低类复杂性 - 认知复杂性 C#
【发布时间】:2021-08-15 20:29:46
【问题描述】:

如何提高代码中的认知复杂性?

我有一个方法,它有 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++;
    }

【问题讨论】:

标签: c# class code-complexity cognitive-complexity


【解决方案1】:

if/else 切换到switch 语句可能是一个好主意,不要从最终代码中丢弃它,但不会降低复杂性,因为“if/else/switch”语句仍然存在于带有其他if 声明。

为避免声纳复杂性,编写更多简单的方法,每个方法都有一个单一目标,最好进行测试,并减少要理解的逻辑。

https://en.wikipedia.org/wiki/SOLID

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

  1. 将主体代码提取到方法中
  2. 将“记录类型”正文代码提取到其他方法
  3. 您仍然可以重构为类(小心,可能是过度工程)
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;
}

看起来你正在编写一个阅读器,所以如果你有很多阅读器/步骤,比如阅读文件的页眉、正文、页脚,以及详细信息和递归内容,你可以将每个片段分隔在一个单独的类中,如 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;
    }
}

使用单独的阅读器,您可以将IYourCustomFileFragmentReaderInterface 分组,调用Test(),如果为真,则调用Read 方法。

【讨论】:

  • 非常感谢 Leo 的详细解释
猜你喜欢
  • 2021-09-22
  • 1970-01-01
  • 2021-06-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-19
  • 2021-01-23
  • 1970-01-01
相关资源
最近更新 更多