Will
Will

Reputation: 3585

Yet Another Stupid Task.ContinueWith Issue

The following works :

public static void Main( string[] args ){
    Task FooTask = Task.Run( ( ) => Console.WriteLine( "Bar" )
        ).ContinueWith( T => Console.WriteLine( "Baz" ) );
    FooTask.Wait( );
    Console.WriteLine( "Press Enter To Exit." );
    Console.ReadLine( );
}

The following does not - ( Bar is printed, Baz is not ).

static void printFirstMessage( ){
    console.WriteLine( "Bar" );
}

static void printFirstMessage( ){
    Console.WriteLine( "Baz" );
}

public static void Main( string[] args ){
    //I say "new Action( ... )" because if I don't, I get an IDE error
    //that says "The call is ambiguous between..."
    Task FooTask = Task.Run( new Action( printFirstMessage )
        ).ContinueWith( new Action( printSecondMessage ) );
    Console.WriteLine( "Press Enter To Exit." );
    Console.ReadLine( );
}

This is an oversimplification of my real issue where I would like to be able to chain two methods together into a task, then do some other stuff, then Wait( ) out the task before exiting the method.

Why does the first instance work fine, but the second instance fail?

Upvotes: 0

Views: 235

Answers (4)

Stephen Cleary
Stephen Cleary

Reputation: 456407

Yet Another Stupid Task.ContinueWith Issue

You shouldn't be using ContinueWith. It's a low-level, inherently dangerous API with several non-obvious pitfalls.

Why does the first instance work fine, but the second instance fail?

As Servy answered, it's because ContinueWith doesn't take an Action parameter - it takes Action<Task>. However, this is really the wrong question...

This is an oversimplification of my real issue where I would like to be able to chain two methods together into a task, then do some other stuff, then Wait( ) out the task before exiting the method.

The proper way to chain is to use await:

private static async Task DoBothAsync()
{
  await Task.Run(() => Console.WriteLine("Bar"));
  Console.WriteLine("Baz");
}

public static void Main(string[] args)
{
  Task FooTask = DoBothAsync();
  FooTask.Wait();
  Console.WriteLine("Press Enter To Exit.");
  Console.ReadLine();
}

Also, I find the use of Task.Run questionable. It's probably not necessary.

Upvotes: 1

VilladsR
VilladsR

Reputation: 350

Task.Run() returns an awaitable Task, which you on which you call ContinueWith. ContinueWith also returns an awaitable Task, which is why you'll need to return something from your ContinueWith call. Try this, which will let you wait for the second task (t) (the printSecondMessage action):

Task FooTask = Task.Run(() => printFirstMessage())
                            .ContinueWith(t => printSecondMessage());

FooTask.Wait();

Upvotes: 0

Servy
Servy

Reputation: 203814

ContinueWith doesn't accept an Action as the first parameter. There are in fact quite a lot of different overloads, but all of them accept a delegate that takes a Task, along with potentially other parameters, and different overloads of ContinueWith have additional parameters besides just a delegate.

If you used Action<Task> instead of Action (and provided a method with the appropriate signature) then the code would compile, as your first example does.

Upvotes: 3

Kevin Holditch
Kevin Holditch

Reputation: 5303

The syntax you have specified in your second example is incorrect and does not even compile. If you correct the syntax to what I think you are meaning (see below) then the code works the same as the first example:

static void printFirstMessage()
{
     Console.WriteLine("Bar");
}

static void printSecondMessage()
{
    Console.WriteLine("Baz");
}

public static void Main(string[] args)
{
    Task FooTask = Task.Run(() => printFirstMessage())
        .ContinueWith(t => printSecondMessage());
    Console.WriteLine("Press Enter To Exit.");
    Console.ReadLine();
}

Upvotes: 0

Related Questions