2014-02-20 5 views
1

Мне интересно найти пробелы в решении для обработки цепочек асинхронных вызовов в silverlight. Пожалуйста, дайте мне знать, если вы найдете пробелы/проблемы в решении. В качестве альтернативы, если есть другой способ/шаблон для решения проблемы, пожалуйста, укажите мне в правильном направлении.отслеживание асинхронных вызовов

Код не компилируется или протестированы

Проблема

У нас есть требование, чтобы сделать какие-то действия после того, как куча асинхронных вызовов закончены.

Например, назначьте значения по умолчанию элементам управления пользовательским интерфейсом после завершения служебных вызовов.

void Fun() 
{ 
    Servicecall1(); 
    Servicecall2(); 

    //Make sure the following is executed only after the previous async calls are finished. 
    AssignDefaultValues(); 
} 

Решение

Один из способов сделать это сцепление сервис звонков через обратные вызовы. Тем не менее, мне просто интересно, как плохо/хорошо он пытается достичь этого через объект специального асинхронного класса отслеживания выполнения, как показано ниже.

class SomeClass 
{ 
    AsyncMehodCallWatcher _methodcallwatcher = new AsyncMehodCallWatcher();    

     void fun() 
     { 
     _methodcallwatcher.AsyncMethodStartMultipleCall(() => 
      { 
      //this function will be called automatically after the following service calls 
      AssignDefaultValues(); 
      }, 2); 

     Servicecall1(); 
     Servicecall2(); 
     } 

     void Servicecall1() 
     { 
      serviceclient.DoSomething(DoSomethingcallback); 

     } 

     void DoSomethingcallback(object sender, GetCompletedEventArgs arg) 
     { 
      _methodcallwatcher.AsyncCallCompleted(); 
     } 

     void Servicecall2() 
     { 
      serviceclient.DoSomething(DoSomething2callback); 

     } 

     void DoSomething2callback(object sender, GetCompletedEventArgs arg) 
     { 
      _methodcallwatcher.AsyncCallCompleted(); 
     } 
} 

Любой, кому нужно позвонить Servicecall1(), или Servicecall2() должен вызвать AsyncMethodPreCall (нуль).

А вот предлагаемая реализация AsyncMehodCallWatcher

public class AsyncMehodCallWatcher 
    { 
     private int _counter = 0; 

     public AsyncMehodCallWatcher() 
     { 
     } 

     public void AsyncMethodPreCall() 
     { 
      AsyncMethodPreCall(null); 
     } 

     Action _callcompletedaction = null;  

     public void AsyncMethodStartMultipleCall(Action action, int numofcalls) 
     { 
      if (action != null) 
      { 
       if (_callcompletedaction != null) 
       { 
        throw new InvalidOperationException(LocalString.AsyncMehodCallWatcherErrorAsyncCalls); 
       } 

       _callcompletedaction = action;    
       _counter = numofcalls; 
      } 
     } 

     public void AsyncMethodPreCall(Action action) 
     { 
      if (action != null) 
      { 
       if (_callcompletedaction != null) 
       { 
        throw new InvalidOperationException(LocalString.AsyncMehodCallWatcherErrorAsyncCalls); 
       } 
       _callcompletedaction = action;    
      } 
      _counter++;   
     } 

     public void AsyncCallCompleted() 
     { 
      _counter--; 

      if (_counter < 0) 
      { 
       throw new InvalidOperationException(LocalString.AsyncMehodCallWatcherErrorAsyncCalls); 
      } 

      if (_counter == 0) 
      { 
       if (_callcompletedaction != null) 
       { 
        _callcompletedaction(); 
        _callcompletedaction = null;     
       } 
      }   
     } 

    } 
+0

В чем вопрос – Sajeetharan

+0

Для упомянутой проблемы предлагается приемлемое решение или любой другой способ? – Jimmy

+0

Вы ориентируетесь на Silverlight Noseratio

ответ

1

Вот что я имел в виду в комментариях к вопросу:

Task<GetCompletedEventArgs> CallServiceAsync(
    Action<Action<object, GetCompletedEventArgs> callDoSomething) 
{ 
    var tcs = new TaskCompletionSource<GetCompletedEventArgs>(); 
    callDoSomething((sender, arg) => tcs.SetResult(arg)); 
    return tcs.Task; 
} 

async Task AsyncMethodStartMultipleCall(ServiceClient client) 
{ 
    var task1 = CallServiceAsync((callback) => client.DoSomething(callback)); 
    var task2 = CallServiceAsync((callback) => client.DoSomething(callback)); 
    var task3 = CallServiceAsync((callback) => client.DoSomething(callback)); 

    await Task.WhenAll(task1, task2, task3); 
} 

Я настоятельно рекомендую использовать Microsoft.Bcl.Async для Silverlight 4 и .NET 4.0. Он даст вам async/await, если вы используете VS2012 +. Если вы не можете использовать это по какой-либо причине, используйте ContinueWhenAll или пойдите для композиции, например, Then pattern от Stephen Toub, если порядок завершения имеет значение. Пример:

Task AsyncMethodStartMultipleCall(ServiceClient client) 
{ 
    var task1 = CallServiceAsync((callback) => client.DoSomething(callback)); 
    var task2 = CallServiceAsync((callback) => client.DoSomething(callback)); 
    var task3 = CallServiceAsync((callback) => client.DoSomething(callback)); 

    return TaskFactory.ContinueWhenAll(new [] { task1, task2, task3 }, (tasks) => 
    { 
     Debug.Print("All completed!"); 
    }); 
} 

Если вы не собираетесь use async/await, убедитесь, что вы сохраните TaskScheduler.FromCurrentSynchronizationContext() из потока пользовательского интерфейса, и передать его в ContinueWhenAll или ContinueWith, в противном случае продолжение лямбда может быть вызвана на пул потоках.

+0

@Noserito, обратите внимание, что мы все еще в .net 4, до сих пор нет async и ожидаем – Jimmy

+0

@ Jimmy, я настоятельно рекомендую использовать ['Microsoft.Bcl.Async'] (http://www.nuget.org/packages/microsoft .bcl.async) для Silverlight 4 и .NET 4.0. Это даст вам «async/await», если вы используете VS2012 +. Если вы не можете использовать это по какой-либо причине, перейдите к шаблону '' Then' (http://blogs.msdn.com/b/pfxteam/archive/2010/11/21/10094564.aspx) Стивеном Тубом. – Noseratio

+0

@ Noserito, к сожалению, мы все еще в 2010 году. Надеемся, мы скоро обновимся. На данный момент, следуйте методу Стивена Тууба – Jimmy

1

При использовании библиотеки Task Parallel Library вы можете включить методы, основанные обратного вызова Into на основе задач методов с использованием TaskCompletionSource. Вот пример.

public class SomeClass 
{ 
    public async Task Fun() 
    { 
     // execute both service requests at the same time 
     Task<Result> fooTask = ServiceCallAsync1(); 
     Task<Result> barTask = ServiceCallAsync2(); 

     // wait for both of them to be complete. 
     Result[] t = await Task.WhenAll(new[] { fooTask, barTask }); 
     AssignDefaultValues(); 
    } 

    public Task<Result> ServiceCallAsync1() 
    { 
     TaskCompletionSource<Result> completion = new TaskCompletionSource<Result>(); 
     serviceclient.DoSomething(() => 
     { 
      completion.SetResult(new FooResult()); 
     }); 
     return completion.Task; 
    } 

    public Task<Result> ServiceCallAsync2() 
    { 
     TaskCompletionSource<Result> completion = new TaskCompletionSource<Result>(); 
     serviceclient.DoSomething(() => 
     { 
      completion.SetResult(new BarResult()); 
     }); 
     return completion.Task; 
    } 

    private void AssignDefaultValues() 
    { 
    } 
} 
+0

обратите внимание, что мы все еще в .net 4, поэтому не будем асинхронно и ждать – Jimmy

+1

О, но вы можете! Вы можете использовать пакет nuget [Microsoft.Bcl.Async] (https://www.nuget.org/packages/Microsoft.Bcl.Async)! –

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