Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add convenience methods directly on IAsyncAction/Operation to facilitate future optimizations and custom Awaiter/Task types. #1580

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 84 additions & 0 deletions src/Tests/UnitTest/TestComponentCSharp_Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1815,6 +1815,27 @@ public void TestAsyncAction()
Assert.Equal(TaskStatus.Canceled, task.Status);
}

[Fact]
public void TestAsyncActionWait()
{
var asyncAction = TestObject.DoitAsync();
TestObject.CompleteAsync();
asyncAction.Wait();
Assert.Equal(AsyncStatus.Completed, asyncAction.Status);

asyncAction = TestObject.DoitAsync();
TestObject.CompleteAsync(E_FAIL);
var e = Assert.Throws<AggregateException>(() => asyncAction.Wait());
Assert.Equal(E_FAIL, e.InnerException.HResult);
Assert.Equal(AsyncStatus.Error, asyncAction.Status);

asyncAction = TestObject.DoitAsync();
asyncAction.Cancel();
e = Assert.Throws<AggregateException>(() => asyncAction.Wait());
Assert.True(e.InnerException is TaskCanceledException);
Assert.Equal(AsyncStatus.Canceled, asyncAction.Status);
}

[Fact]
public void TestAsyncActionRoundTrip()
{
Expand Down Expand Up @@ -1882,6 +1903,27 @@ public void TestAsyncActionWithProgress()
Assert.Equal(TaskStatus.Canceled, task.Status);
}

[Fact]
public void TestAsyncActionWithProgressWait()
{
var asyncAction = TestObject.DoitAsyncWithProgress();
TestObject.CompleteAsync();
asyncAction.Wait();
Assert.Equal(AsyncStatus.Completed, asyncAction.Status);

asyncAction = TestObject.DoitAsyncWithProgress();
TestObject.CompleteAsync(E_FAIL);
var e = Assert.Throws<AggregateException>(() => asyncAction.Wait());
Assert.Equal(E_FAIL, e.InnerException.HResult);
Assert.Equal(AsyncStatus.Error, asyncAction.Status);

asyncAction = TestObject.DoitAsyncWithProgress();
asyncAction.Cancel();
e = Assert.Throws<AggregateException>(() => asyncAction.Wait());
Assert.True(e.InnerException is TaskCanceledException);
Assert.Equal(AsyncStatus.Canceled, asyncAction.Status);
}

async Task<int> InvokeAddAsync(int lhs, int rhs)
{
return await TestObject.AddAsync(lhs, rhs);
Expand Down Expand Up @@ -1913,6 +1955,27 @@ public void TestAsyncOperation()
Assert.Equal(TaskStatus.Canceled, task.Status);
}

[Fact]
public void TestAsyncOperationWait()
{
var asyncOperation = TestObject.AddAsync(42, 8);
TestObject.CompleteAsync();
asyncOperation.Wait();
Assert.Equal(AsyncStatus.Completed, asyncOperation.Status);

asyncOperation = TestObject.AddAsync(42, 8);
TestObject.CompleteAsync(E_FAIL);
var e = Assert.Throws<AggregateException>(() => asyncOperation.Wait());
Assert.Equal(E_FAIL, e.InnerException.HResult);
Assert.Equal(AsyncStatus.Error, asyncOperation.Status);

asyncOperation = TestObject.AddAsync(42, 8);
asyncOperation.Cancel();
e = Assert.Throws<AggregateException>(() => asyncOperation.Wait());
Assert.True(e.InnerException is TaskCanceledException);
Assert.Equal(AsyncStatus.Canceled, asyncOperation.Status);
}


[Fact]
public void TestAsyncOperationRoundTrip()
Expand Down Expand Up @@ -1983,6 +2046,27 @@ public void TestAsyncOperationWithProgress()
Assert.Equal(TaskStatus.Canceled, task.Status);
}

[Fact]
public void TestAsyncOperationWithProgressWait()
{
var asyncOperation = TestObject.AddAsyncWithProgress(42, 8);
TestObject.CompleteAsync();
asyncOperation.Wait();
Assert.Equal(AsyncStatus.Completed, asyncOperation.Status);

asyncOperation = TestObject.AddAsyncWithProgress(42, 8);
TestObject.CompleteAsync(E_FAIL);
var e = Assert.Throws<AggregateException>(() => asyncOperation.Wait());
Assert.Equal(E_FAIL, e.InnerException.HResult);
Assert.Equal(AsyncStatus.Error, asyncOperation.Status);

asyncOperation = TestObject.AddAsyncWithProgress(42, 8);
asyncOperation.Cancel();
e = Assert.Throws<AggregateException>(() => asyncOperation.Wait());
Assert.True(e.InnerException is TaskCanceledException);
Assert.Equal(AsyncStatus.Canceled, asyncOperation.Status);
}

[Fact]
public void TestPointTypeMapping()
{
Expand Down
49 changes: 40 additions & 9 deletions src/cswinrt/strings/additions/Windows.Foundation/AsyncInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -121,39 +121,38 @@ public static IAsyncOperationWithProgress<TResult, TProgress> Run<TResult, TProg

#region Factory methods for creating IAsyncInfo instances that have already completed synchronously

internal static IAsyncAction CreateCompletedAction()
public static IAsyncAction CompletedAction()
{
var asyncInfo = new TaskToAsyncActionAdapter(isCanceled: false);
return asyncInfo;
}


internal static IAsyncActionWithProgress<TProgress> CreateCompletedAction<TProgress>()
public static IAsyncActionWithProgress<TProgress> CompletedActionWithProgress<TProgress>()
{
var asyncInfo = new TaskToAsyncActionWithProgressAdapter<TProgress>(isCanceled: false);
return asyncInfo;
}


internal static IAsyncOperation<TResult> CreateCompletedOperation<TResult>(TResult synchronousResult)
public static IAsyncOperation<TResult> FromResult<TResult>(TResult synchronousResult)
{
var asyncInfo = new TaskToAsyncOperationAdapter<TResult>(synchronousResult);
return asyncInfo;
}


internal static IAsyncOperationWithProgress<TResult, TProgress> CreateCompletedOperation<TResult, TProgress>(TResult synchronousResult)
public static IAsyncOperationWithProgress<TResult, TProgress> FromResultWithProgress<TResult, TProgress>(TResult synchronousResult)
{
var asyncInfo = new TaskToAsyncOperationWithProgressAdapter<TResult, TProgress>(synchronousResult);
return asyncInfo;
}

#endregion Factory methods for creating IAsyncInfo instances that have already completed synchronously


#region Factory methods for creating IAsyncInfo instances that have already completed synchronously with an error

internal static IAsyncAction CreateFaultedAction(Exception error)
public static IAsyncAction FromException(Exception error)
{
if (error == null)
throw new ArgumentNullException(nameof(error));
Expand All @@ -167,7 +166,7 @@ internal static IAsyncAction CreateFaultedAction(Exception error)
}


internal static IAsyncActionWithProgress<TProgress> CreateFaultedAction<TProgress>(Exception error)
public static IAsyncActionWithProgress<TProgress> FromExceptionWithProgress<TProgress>(Exception error)
{
if (error == null)
throw new ArgumentNullException(nameof(error));
Expand All @@ -181,7 +180,7 @@ internal static IAsyncActionWithProgress<TProgress> CreateFaultedAction<TProgres
}


internal static IAsyncOperation<TResult> CreateFaultedOperation<TResult>(Exception error)
public static IAsyncOperation<TResult> FromException<TResult>(Exception error)
{
if (error == null)
throw new ArgumentNullException(nameof(error));
Expand All @@ -195,7 +194,7 @@ internal static IAsyncOperation<TResult> CreateFaultedOperation<TResult>(Excepti
}


internal static IAsyncOperationWithProgress<TResult, TProgress> CreateFaultedOperation<TResult, TProgress>(Exception error)
public static IAsyncOperationWithProgress<TResult, TProgress> FromExceptionWithProgress<TResult, TProgress>(Exception error)
{
if (error == null)
throw new ArgumentNullException(nameof(error));
Expand All @@ -207,7 +206,39 @@ internal static IAsyncOperationWithProgress<TResult, TProgress> CreateFaultedOpe

return asyncInfo;
}

#endregion Factory methods for creating IAsyncInfo instances that have already completed synchronously with an error

#region Factory methods for creating IAsyncInfo instances that have already been canceled synchronously

public static IAsyncAction CanceledAction()
{
var asyncInfo = new TaskToAsyncActionAdapter(isCanceled: true);
return asyncInfo;
}


public static IAsyncActionWithProgress<TProgress> CanceledActionWithProgress<TProgress>()
{
var asyncInfo = new TaskToAsyncActionWithProgressAdapter<TProgress>(isCanceled: true);
return asyncInfo;
}


public static IAsyncOperation<TResult> CanceledOperation<TResult>()
{
var asyncInfo = new TaskToAsyncOperationAdapter<TResult>(isCanceled: true);
return asyncInfo;
}


public static IAsyncOperationWithProgress<TResult, TProgress> CanceledOperationWithProgress<TResult, TProgress>()
{
var asyncInfo = new TaskToAsyncOperationWithProgressAdapter<TResult, TProgress>(isCanceled: true);
return asyncInfo;
}

#endregion Factory methods for creating IAsyncInfo instances that have already been canceled synchronously

} // class AsyncInfo
} // namespace
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,13 @@ internal TaskToAsyncOperationAdapter(TResult synchronousResult)
{
}

internal TaskToAsyncOperationAdapter(bool isCanceled)
: base(default(TResult))
{
if (isCanceled)
DangerousSetCanceled();
}

public TResult GetResults()
{
return GetResultsInternal();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,13 @@ internal TaskToAsyncOperationWithProgressAdapter(TResult synchronousResult)
{
}

internal TaskToAsyncOperationWithProgressAdapter(bool isCanceled)
: base(default(TResult))
{
if (isCanceled)
DangerousSetCanceled();
}

public TResult GetResults()
{
return GetResultsInternal();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@ public static TaskAwaiter GetAwaiter(this IAsyncAction source)
return AsTask(source).GetAwaiter();
}

public static void Wait(this IAsyncAction source)
{
AsTask(source).Wait();
}

public static Task<TResult> AsTask<TResult>(this IAsyncOperation<TResult> source, CancellationToken cancellationToken)
{
if (source == null)
Expand Down Expand Up @@ -104,6 +109,16 @@ public static TaskAwaiter<TResult> GetAwaiter<TResult>(this IAsyncOperation<TRes
return AsTask(source).GetAwaiter();
}

public static void Wait<TResult>(this IAsyncOperation<TResult> source)
{
AsTask(source).Wait();
}

public static TResult Get<TResult>(this IAsyncOperation<TResult> source)
{
return AsTask(source).Result;
}

public static Task AsTask<TProgress>(this IAsyncActionWithProgress<TProgress> source, CancellationToken cancellationToken, IProgress<TProgress> progress)
{
if (source == null)
Expand Down Expand Up @@ -169,6 +184,11 @@ public static TaskAwaiter GetAwaiter<TProgress>(this IAsyncActionWithProgress<TP
return AsTask(source).GetAwaiter();
}

public static void Wait<TProgress>(this IAsyncActionWithProgress<TProgress> source)
{
AsTask(source).Wait();
}

public static Task<TResult> AsTask<TResult, TProgress>(this IAsyncOperationWithProgress<TResult, TProgress> source, CancellationToken cancellationToken, IProgress<TProgress> progress)
{
if (source == null)
Expand Down Expand Up @@ -234,6 +254,16 @@ public static TaskAwaiter<TResult> GetAwaiter<TResult, TProgress>(this IAsyncOpe
return AsTask(source).GetAwaiter();
}

public static void Wait<TResult, TProgress>(this IAsyncOperationWithProgress<TResult, TProgress> source)
{
AsTask(source).Wait();
}

public static TResult Get<TResult, TProgress>(this IAsyncOperationWithProgress<TResult, TProgress> source)
{
return AsTask(source).Result;
}

public static IAsyncAction AsAsyncAction(this Task source)
{
if (source == null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,11 @@ internal static IAsyncOperationWithProgress<IBuffer, uint> ReadAsync_MemoryStrea
if (dataBuffer.Length > 0)
memStream.Seek(dataBuffer.Length, SeekOrigin.Current);

return AsyncInfo.CreateCompletedOperation<IBuffer, uint>(dataBuffer);
return AsyncInfo.FromResultWithProgress<IBuffer, uint>(dataBuffer);
}
catch (Exception ex)
{
return AsyncInfo.CreateFaultedOperation<IBuffer, uint>(ex);
return AsyncInfo.FromExceptionWithProgress<IBuffer, uint>(ex);
}
} // ReadAsync_MemoryStream

Expand Down