Print Page | Close Window

AsyncParallelTaskCompletedArgs cannot be converted to AsyncEventArgs

Printed From: IdeaBlade
Category: DevForce
Forum Name: DevForce 2009
Forum Discription: For .NET 3.5
URL: http://www.ideablade.com/forum/forum_posts.asp?TID=1388
Printed Date: 28-Apr-2025 at 12:32pm


Topic: AsyncParallelTaskCompletedArgs cannot be converted to AsyncEventArgs
Posted By: skingaby
Subject: AsyncParallelTaskCompletedArgs cannot be converted to AsyncEventArgs
Date Posted: 23-Jul-2009 at 11:33am
I've created the following unit test:

[TestMethod]

[Asynchronous]
public void TestLockedMonth()
{
    _em = new DomainModel.DomainModelEntityManager();
    var task1 = AsyncSerialTask.Create();
    var task2 = task1.AddAsyncLogin(_em, new LoginCredential(null, null, null));
    var task3 = task2.AddAction(x => Assert.IsTrue(_em.IsLoggedIn));
    var task4 = task3.AddAction(x => Assert.IsTrue(_em.IsConnected));
    var task5 = task4.AddAsyncAction<AsyncParallelTaskCompletedArgs>((loginEventArgs, callback) => LocalEntityManager.InitializeCacheAsync(callback));
    EnqueueCallback(() => task5.Execute(null, args => TestLockedMonthCallback(args)));
}


The InitializeCacheAsync method looks like this:
public static void InitializeCacheAsync(Action<AsyncParallelTaskCompletedArgs> callback)

{
    var task = AsyncParallelTask.Create();
    task.AddAsyncQuery(1, x => _defaultManager.AccountingMonths);
    task.AddAsyncQuery(2, x => _defaultManager.DealTypes);
    task.Execute(callback);
}


This compiler error shows:
The type 'IdeaBlade.EntityModel.AsyncParallelTaskCompletedArgs' cannot be used as type parameter 'T2' in the generic type or method 'IdeaBlade.EntityModel.AsyncSerialTask<T0,T1>.AddAsyncAction<T2>(System.Action<T1,IdeaBlade.EntityModel.AsyncCompletedCallback<T2>>)'. There is no implicit reference conversion from 'IdeaBlade.EntityModel.AsyncParallelTaskCompletedArgs' to 'IdeaBlade.EntityModel.AsyncEventArgs'.

Is something I can work around? Thanks, Simon.



Replies:
Posted By: kimj
Date Posted: 23-Jul-2009 at 6:42pm
The async actions in the AsyncSerialTask expect an AsyncCompletedCallback of AsyncEventArgs or a sub-type, and unfortunately the AsyncParallelTaskCompletedArgs aren't a sub-type of AsyncEventArgs.  We'll look at fixing this.
 
Meanwhile, you can still do what you need, but with a bit more work.  Since you can't use AddAsyncAction<AsyncParallelTaskCompletedArgs> with the serial task, you need to insert a dummy action here to tie the results of the parallel task back to the serial task.  There are probably more clever ways to do this, but here's one -
 

    public void TestLockedMonth() {
      _em = new DomainModel.DomainModelEntityManager();
      var task1 = AsyncSerialTask.Create();
      var task2 = task1.AddAsyncLogin(_em1, new LoginCredential(null, null, null));
      var task3 = task2.AddAction(x => Assert.IsTrue(_em1.IsLoggedIn));
      var task4 = task3.AddAction(x => Assert.IsTrue(_em1.IsConnected));
      var task5 = task4.AddAsyncAction<AsyncEventArgs>((x, cb) => InitializeCacheAsync(cb, TestLockedMonthCallback));
      EnqueueCallback(() => task5.Execute(null, args => TestLockedMonthCallback2(args)));
    }
    // Take 2 args here - 1 the serial task callback, the other the parallel task completion action.
    public void InitializeCacheAsync(AsyncCompletedCallback<AsyncEventArgs> serialCB, Action<AsyncParallelTaskCompletedArgs> completionAction) {
      var task = AsyncParallelTask.Create();
      task.AddAsyncQuery(1, x => _defaultManager.AccountingMonths);
      task.AddAsyncQuery(2, x => _defaultManager.DealTypes);
      // Any object can be passed as input and available to the completion action.
      task.Execute(serialCB, completionAction);
    }
    // Parallel task completion action
    public void TestLockedMonthCallback(AsyncParallelTaskCompletedArgs args) {
      // We passed this callback as input parm into the AsyncParallelTask
      var serialCB = args.ExecutionInput as AsyncCompletedCallback<AsyncEventArgs>;
      // Build new args, taking advantage of userState input argument.
      AsyncEventArgs newArgs = null;
      if (args.Ok) {
        // This is arbitrary - here we supply parallel task completion info ...
        newArgs = new AsyncEventArgs(args.CompletionMap);
      } else {
        // Also arbitrary - if parallel task failed provide some info ...
        newArgs = new AsyncEventArgs(args.Errors[0].Exception, false, args.Errors);
      }
      // Now call the serial task's callback action.
      serialCB(newArgs);
    }
    // Called when serial task completes.
    public void TestLockedMonthCallback2(AsyncSerialTaskCompletedArgs<AsyncEventArgs> args) {
      // Result here is the result from the parallel task completion.
      var result = args.Result;
      var completionMap = result.UserState as Dictionary<object, AsyncEventArgs>;
      TestExit();
    }


Posted By: skingaby
Date Posted: 29-Jul-2009 at 6:53am
This was a really slick workaround. It works like a charm. I have even used this in the middle of a longer stack of serial tasks (i.e. calling InitializeCache and then doing some other things afterwards). Very nice. Thank you for your help!



Print Page | Close Window