Снижение сложности класса - когнитивная сложность C#

Пожалуйста, посоветуйте мне, как я могу улучшить когнитивную сложность моего кода.

У меня есть метод, в котором есть цикл while, и внутри этого множества блоков IF ELSE я попытался удалить IF ELSE с помощью операторов SWITCH, но не улучшил когнитивную сложность в соответствии с анализом куба 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++;
    }

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;
}

Похоже, вы пишете ридер, поэтому, если у вас много читателей / шагов, таких как чтение заголовка, тела, нижнего колонтитула файла, с деталями и рекурсивным содержимым, вы можете разделить каждый фрагмент в отдельный класс, например 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;
    }
}

С отдельными читателями вы можете сгруппировать в список IYourCustomFileFragmentReaderInterface, вызов Test() и если это правда, то вызовите Read метод.

Другие вопросы по тегам