Страницы

Поиск по вопросам

четверг, 9 января 2020 г.

Запомнить точку выполнения метода и продолжить работу с неё

#c_sharp


    public interface IService 
    {
    bool Process(Info info, SshTunnel ssh);
    }

    public class Service : IService
    {

       public bool Process(Info info, SshTunnel ssh)
       {
         var personalInfo = new GetPersonalInfo(ssh);

         if (personalInfo == null) return false;

         var totalPoints = GetTotalPoints(ssh);

         if (personalInfo == null) return false;

         return true;
       }

       private SomeInfo GetPersonalInfo(SshTunnel ssh)
       {
         //Example
         try
         {
            //Get personal info
         }
         catch(NetworkException ex)
         {

         }

         return new SomeInfo();
        }

       private SomeInfo GetTotalPoints(SshTunnel ssh)
       {
         //Example
         try
         {
            //Get total points
         }
         catch (NetworkException ex)
         {
            //
         }

         return new SomeInfo();
        }
}


Есть 2 варианта работы данного класса если в каком-то из методов GetTotalPoints или
GetPersonalInfo упал ssh:


Сразу же заменить его на новый и продолжить работу (С того метода, в котором он упал,
что бы не запрашивать заново уже полученные данные. Например если ssh перестал работать
в GetTotalPoints, а GetPersonalInfo успешно получил данные)
Получить новый ssh и запрашивать данные через него с самого начала, даже если один
из методов успешно получил данные.


Проблема следующая.. В случае, когда мне нужно получить новый туннель и начать выполнение
метода Process с самого начала, без сохранения прогресса, я просто возвращаю false,
получаю новый туннель и запускаю данный метод заново. А вот как сделать второй случай,
когда мне не нужно начинать выполнение заново, а именно с того места, в котором туннель
упал, что бы не запрашивать уже полученные данные заново, я не понимаю как!

Класс, который это всё запускает

public class Processer
{
    private IService service;
    private InfoSource infoSource;
    private SshList sshList;

    public Processer(IService _service)
    {
        service = _service;
        infoSource = Map.GetInfoSource();
        sshList = Map.GetSSHList();
    }

    public void Run()
    {
        // Случай, когда нужно выполнить метод без сохранения прогресса (с начала)
        bool IsPassed;
        var info = infoSource.Take();

        do
        {
            var ssh = sshList.Take();
            IsPassed = service.Process(info, ssh);

        } while (!IsPassed);
    }
}

    


Ответы

Ответ 1



Вам нужно реализовать простенький конечный автомат. Ваш класс может выглядеть так, и вы сможете добавлять новые шаги, если понадобиться: public class Service : IService { private enum State { Begin, GetPersonalInfo, GetTotalPoints, End } private State _state = State.Begin; public bool Process(Info info, SshTunnel ssh) { while (true) { switch (_state) { case State.Begin: _state = State.GetPersonalInfo; break; case State.GetPersonalInfo: var personalInfo = GetPersonalInfo(ssh); if (personalInfo == null) return false; else _state = State.GetTotalPoints; break; case State.GetTotalPoints: var totalPoints = GetTotalPoints(ssh); if (totalPoints == null) return false; else _state = State.End; break; case State.End: return true; } } } // ... } Так как компилятор сам умеет строить такие автоматы (для асинхронных методов, или для методов использующих yield), то можно поручить эту работу ему. Пример: public interface IService { } public class Info { } public class SshTunnel { } public class Service : IService { private SshTunnel _ssh; private IEnumerator _proccessStateMachine; public bool Process(Info info, SshTunnel ssh) { _ssh = ssh; if (_proccessStateMachine == null) // извлекаем IEnumerator _proccessStateMachine = ProcessInternal().GetEnumerator(); _proccessStateMachine.MoveNext(); return _proccessStateMachine.Current; } private IEnumerable ProcessInternal() { // код выглядит как обычный, только с yield while (true) { var personalInfo = GetPersonalInfo(_ssh); if (personalInfo == null) yield return false; else break; } while (true) { var totalPoints = GetTotalPoints(_ssh); if (totalPoints == null) yield return false; else break; } yield return true; } // эмуляция нестабильной работы private int counter; private object GetPersonalInfo(SshTunnel ssh) { Console.WriteLine("GetPersonalInfo"); Thread.Sleep(300); if (++counter % 5 == 0) return new object(); return null; } private object GetTotalPoints(SshTunnel ssh) { Console.WriteLine("GetTotalPoints"); Thread.Sleep(300); if (++counter % 5 == 0) return new object(); return null; } } static class Program { static void Main(string[] args) { var service = new Service(); while (!service.Process(null, null)) ; } }

Комментариев нет:

Отправить комментарий