Skip to content

Instantly share code, notes, and snippets.

@negativeeddy
Last active February 18, 2016 14:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save negativeeddy/a0a363c6fe9e0316502d to your computer and use it in GitHub Desktop.
Save negativeeddy/a0a363c6fe9e0316502d to your computer and use it in GitHub Desktop.
TPL exception behavior test. This demonstrates exception behavior based on whether the Task is ignored or awaited deep inside a callstack.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace async_exception_test
{
class Program
{
static void Main(string[] args)
{
MainAsync().Wait();
Console.ReadLine();
}
static async Task MainAsync()
{
await RunTests(false);
await RunTests(true);
}
private static async Task RunTests(bool awaitFlag)
{
doAwait = awaitFlag;
for (int i = 0; i < options.Length; i++)
{
try
{
funcID = i;
Console.WriteLine("{0} - {1}",
awaitFlag ? "AWAITING" : "FORGETTING",
options[funcID].Method.Name
);
await FooA();
await Task.Delay(500);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
Console.WriteLine("------------------------------");
}
}
private static async Task FooA()
{
await Task.Delay(10);
await FooB();
await Task.Delay(10);
}
private static async Task FooB()
{
await Task.Delay(10);
await FooC();
await Task.Delay(10);
}
static Func<Task>[] options = new Func<Task>[]
{
ExceptionThrownNoTask,
ExceptionFromTask,
ExceptionBeforeAwaitAsync,
ExceptionAfterAwaitAsync,
};
static int funcID;
static bool doAwait;
private static async Task FooC()
{
Func<Task> theFunc = options[funcID];
if (doAwait)
{
await theFunc();
}
else
{
theFunc().Forget();
}
}
static Task ExceptionThrownNoTask()
{
throw new Exception("BROKEN");
}
static Task ExceptionFromTask()
{
return TaskHelper.FromException(new Exception("BROKEN"));
}
static async Task ExceptionBeforeAwaitAsync()
{
throw new Exception("BROKEN");
await Task.Delay(10);
}
static async Task ExceptionAfterAwaitAsync()
{
await Task.Delay(10);
throw new Exception("BROKEN");
}
}
public static class TaskHelper
{
/// <summary>
/// This method does nothing with the Task. It is used to explicitly mark
/// Tasks as "Fire and Forget" to prevent warning CS1998
/// </summary>
/// <param name="task">The task to ignore</param>
public static void Forget(this Task task)
{
// do nothing
}
private static Task<bool> _completedTask;
public static Task CompletedTask
{
get
{
if (_completedTask == null)
{
_completedTask = Task.FromResult(true);
}
return _completedTask;
}
}
/// <summary>Creates a Taskthat's completed exceptionally with the specified exception.</summary>
/// <param name="exception">The exception with which to complete the task.</param>
/// <returns>The faulted task.</returns>
public static Task FromException(Exception exception)
{
return FromException<bool>(exception);
}
/// <summary>Creates a Task that's completed exceptionally with the specified exception.</summary>
/// <typeparam name="TResult">The type of the result returned by the task.</typeparam>
/// <param name="exception">The exception with which to complete the task.</param>
/// <returns>The faulted task.</returns>
public static Task<TResult> FromException<TResult>(Exception exception)
{
if (exception == null) throw new ArgumentNullException("exception");
TaskCompletionSource<TResult> tsc = new TaskCompletionSource<TResult>();
tsc.SetException(exception);
return tsc.Task;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment