/// <summary>
        /// Выполнить синхронизацию.
        /// </summary>
        public void Sync(
            ISyncContext context,
            TSvc svc,
            int retries,
            ITaskIndicator indicator)
        {
            if (context == null)
                throw new ArgumentNullException("context");
            if (svc == null)
                throw new ArgumentNullException("svc");
            if (indicator == null)
                throw new ArgumentNullException("indicator");

            indicator.SetTaskState(SyncTaskState.Sync);
            try
            {
                context.CheckState();

                indicator.SetStatusText(SyncResources.IndicatorPrepareRequest);
                var rq = PrepareRequest(context);
                if (rq == null)
                    return; // Nothing to do

                context.CheckState();

                indicator.SetStatusText(SyncResources.IndicatorMakeRequest);
                var rsp = context.CallWithRetries(rq, GetDisplayName(), retries,
                    () => MakeRequest(context, svc, rq));

                context.CheckState();

                indicator.SetStatusText(SyncResources.IndicatorProcessResponse);
                ProcessResponse(context, rq, rsp);

                context.CheckState();

                indicator.SetTaskState(SyncTaskState.Succeed);
                indicator.SetStatusText(SyncResources.IndicatorSuccessFinish);
            }
            // Отмену пользователем не трактуем как ошибку и выкидываем наверх
            catch (UserCancelledException)
            {
                throw;
            }
            catch (Exception ex)
            {
                indicator.SetTaskState(SyncTaskState.Failed);
                indicator.SetStatusText(ex.Message);
                context.TryAddSyncError(
                    new SyncErrorInfo(SyncErrorType.CriticalError, GetDisplayName(), ex.ToString()));
            }
        }