2016-09-23 1 views
1

Я реализовал уже опросника на основе таймера. В качестве примера вы можете думать о TryConnect на стороне клиента - я звоню TryConnect, и он будет соединять в конце концов через некоторое время. Он обрабатывает несколько потоков, если соединение находится в процессе, все последующие TryConnect немедленно возвращается без каких-либо дополнительных действий. Внутри я просто создаю таймер и в промежутках, которые я пытаюсь подключить, - если соединение терпит неудачу, я попробую еще раз. И так далее.Как совместить опрос временной базы с ожидаемой задачей

Небольшой недостаток в том, что «огонь & забыть» картину, и теперь я хотел бы объединить его с «асинхронном/ждать» шаблон, т.е. вместо вызова:

client.TryConnect(); // returns immediately 
// cannot tell if I am connected at this point 

Я хотел бы назвать это так :

await client.TryConnect(); 
// I am connected for sure 

Как я могу изменить свою реализацию для поддержки «async/await»? Я думал о создании пустого Task (только для await), а затем заполните его FromResult, но этот метод создает новую задачу, она не заполняет данный экземпляр.

Для записи, текущая реализация выглядит следующим образом (только эскиз кода):

public void TryConnect() 
{ 
    if (this.timer!=null) 
    { 
    this.timer = new Timer(_ => tryConnect(),null,-1,-1); 
    this.timer.Change(0,-1); 
    } 
} 
private void tryConnect() 
{ 
    if (/*connection failed*/) 
    this.timer.Change(interval,-1); 
    else 
    this.timer = null; 
} 
+0

Как само соединение осуществляется? Используется ли какая-либо функция async? – YuvShap

+0

Что вы хотите достичь, сделав это? – usr

ответ

1

Не имея хорошую Minimal, Complete, and Verifiable code example это невозможно предложить какие-либо конкретные предложения. Учитывая то, что вы написали, это возможно, что вы ищете, TaskCompletionSource. Например:

private TaskCompletionSource<bool> _tcs; 

public async Task TryConnect() 
{ 
    if (/* no connection exists */) 
    { 
    if (_tcs == null) 
    { 
     this.timer = new Timer(_ => tryConnect(),null,-1,-1); 
     this.timer.Change(0,-1); 
     _tcs = new TaskCompletionSource<bool>(); 
    } 

    await _tcs.Task; 
    } 
} 

private void tryConnect() 
{ 
    if (/*connection failed*/) 
    this.timer.Change(interval,-1); 
    else 
    { 
    _tcs.SetResult(true); 
    _tcs = null; 
    this.timer = null; 
    } 
} 

Примечания:

  • Ваш исходный код примера будет повторить логику соединения, если TryConnect() вызывается снова после подключения. Я ожидаю, что вы действительно хотите, чтобы проверить наличие действительного соединения, поэтому я немного изменил приведенное выше, чтобы проверить это. Вы можете, конечно, удалить эту часть, если вы действительно хотите попробовать новое соединение, даже если оно уже существует.
  • Наборы кода _tcs - null сразу после установки его результата. Обратите внимание, что любой код, ожидающий или иным образом хранящий значение Task для объекта _tcs, будет неявно ссылаться на текущий объект _tcs, поэтому здесь не проблема сбросить ссылку на поле.
  • Нет не общего TaskCompletionSource. Поэтому для сценариев, где вам просто нужен Task, вы можете использовать общий тип с типом-заполнителем, например bool, как я здесь делал, или object или что-то еще. Я мог бы позвонить SetResult(false) так же, как и SetResult(true), и это не имело бы значения в этом примере. Все, что имеет значение, - это то, что завершено Task, а не какое значение возвращается.
  • В приведенном выше примере используется ключевое слово async, чтобы сделать TryConnect() методом async. ИМХО, это немного более читаемо, но, конечно же, он несет небольшие накладные расходы в дополнительном Task для представления операции метода.Если вы предпочитаете, вы можете сделать то же самое непосредственно без метода async:
public Task TryConnect() 
{ 
    if (/* no connection exists */) 
    { 
    if (_tcs == null) 
    { 
     this.timer = new Timer(_ => tryConnect(),null,-1,-1); 
     this.timer.Change(0,-1); 
     _tcs = new TaskCompletionSource<bool>(); 
    } 

    return _tcs.Task; 
    } 

    return Task.CompletedTask; 
} 
+0

'TaskCompletionSource' - это все, что мне нужно, к сожалению, я не знал о существовании этого класса - до сих пор :-), так много спасибо вам за вашу помощь! – astrowalker

Смежные вопросы