Skip to content

Commit 3caefec

Browse files
Merge pull request #3 from brminnick/v1.0
V1.0
2 parents 14e4a8c + c7bbcff commit 3caefec

File tree

11 files changed

+55
-52
lines changed

11 files changed

+55
-52
lines changed

README.md

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,16 @@ Extensions for `System.Threading.Tasks.Task`, inspired by [John Thiriet](https:/
3939
An extension method to safely fire-and-forget a `Task`:
4040
- `SafeFireAndForget`
4141

42+
```csharp
43+
public static async void SafeFireAndForget(this System.Threading.Tasks.Task task, bool continueOnCapturedContext = true, System.Action<System.Exception> onException = null)
44+
```
45+
4246
```csharp
4347
void HandleButtonTapped(object sender, EventArgs e)
4448
{
4549
// Allows the async Task method to safely run on a different thread while not awaiting its completion
46-
ExampleAsyncMethod().SafeFireAndForget();
50+
// If an exception is thrown, Console.WriteLine
51+
ExampleAsyncMethod().SafeFireAndForget(onException: ex => Console.WriteLine(ex.Message));
4752

4853
// HandleButtonTapped continues execution here while `ExampleAsyncMethod()` is running on a different thread
4954
// ...
@@ -62,6 +67,22 @@ Allows for `Task` to safely be used asynchronously with `ICommand`:
6267
- `AsyncCommand : IAsyncCommand`
6368
- `IAsyncCommand : ICommand`
6469

70+
71+
```csharp
72+
public AsyncCommand(Func<T, Task> execute,
73+
Func<object, bool> canExecute = null,
74+
Action<Exception> onException = null,
75+
bool continueOnCapturedContext = true)
76+
```
77+
78+
```csharp
79+
public AsyncCommand(Func<Task> execute,
80+
Func<object, bool> canExecute = null,
81+
Action<Exception> onException = null,
82+
bool continueOnCapturedContext = true)
83+
```
84+
85+
6586
```csharp
6687
public class ExampleClass
6788
{

Src/AsyncAwaitBestPractices.MVVM.nuspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
33
<metadata minClientVersion="2.5">
44
<id>AsyncAwaitBestPractices.MVVM</id>
5-
<version>0.9.0</version>
5+
<version>1.0.0</version>
66
<title>Task Extensions for MVVM</title>
77
<authors>Brandon Minnick, John Thiriet</authors>
88
<owners>Brandon Minnick</owners>

Src/AsyncAwaitBestPractices.MVVM/AsyncCommand.cs

Lines changed: 17 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,13 @@ public sealed class AsyncCommand<T> : IAsyncCommand
2121
/// Initializes a new instance of the <see cref="T:TaskExtensions.MVVM.AsyncCommand`1"/> class.
2222
/// </summary>
2323
/// <param name="execute">The Function executed when Execute or ExecuteAysnc is called. This does not check canExecute before executing and will execute even if canExecute is false</param>
24-
/// <param name="continueOnCapturedContext">If set to <c>true</c> continue on captured context; this will ensure that the Synchronization Context returns to the calling thread. If set to <c>false</c> continue on a different context; this will allow the Synchronization Context to continue on a different thread</param>
25-
/// <param name="onException">If an exception is thrown in the Task, <c>onException</c> will execute. If onException is null, the exception will be re-thrown</param>
2624
/// <param name="canExecute">The Function that verifies whether or not AsyncCommand should execute.</param>
25+
/// <param name="onException">If an exception is thrown in the Task, <c>onException</c> will execute. If onException is null, the exception will be re-thrown</param>
26+
/// <param name="continueOnCapturedContext">If set to <c>true</c> continue on captured context; this will ensure that the Synchronization Context returns to the calling thread. If set to <c>false</c> continue on a different context; this will allow the Synchronization Context to continue on a different thread</param>
2727
public AsyncCommand(Func<T, Task> execute,
28-
bool continueOnCapturedContext = true,
28+
Func<object, bool> canExecute = null,
2929
Action<Exception> onException = null,
30-
Func<object, bool> canExecute = null)
30+
bool continueOnCapturedContext = true)
3131
{
3232
_execute = execute;
3333
_continueOnCapturedContext = continueOnCapturedContext;
@@ -71,35 +71,22 @@ public AsyncCommand(Func<T, Task> execute,
7171
/// <param name="parameter">Data used by the command. If the command does not require data to be passed, this object can be set to null.</param>
7272
public Task ExecuteAsync(object parameter)
7373
{
74-
switch (parameter)
75-
{
76-
case T validParameter:
77-
return ExecuteAsync(validParameter);
78-
79-
case null when !typeof(T).IsValueType:
80-
81-
return ExecuteAsync((T)parameter);
74+
if (parameter is T validParameter)
75+
return ExecuteAsync(validParameter);
76+
else if (parameter is null && !typeof(T).IsValueType)
77+
return ExecuteAsync((T)parameter);
8278

83-
default:
84-
throw new InvalidCommandParameterException(typeof(T), parameter.GetType());
85-
}
79+
throw new InvalidCommandParameterException(typeof(T), parameter.GetType());
8680
}
8781

8882
void ICommand.Execute(object parameter)
8983
{
90-
switch (parameter)
91-
{
92-
case T validParameter:
93-
_execute?.Invoke(validParameter)?.SafeFireAndForget(_continueOnCapturedContext, _onException);
94-
break;
95-
96-
case null when !typeof(T).IsValueType:
97-
_execute?.Invoke((T)parameter)?.SafeFireAndForget(_continueOnCapturedContext, _onException);
98-
break;
99-
100-
default:
101-
throw new InvalidCommandParameterException(typeof(T), parameter.GetType());
102-
}
84+
if (parameter is T validParameter)
85+
_execute?.Invoke(validParameter)?.SafeFireAndForget(_continueOnCapturedContext, _onException);
86+
else if (parameter is null && !typeof(T).IsValueType)
87+
_execute?.Invoke((T)parameter)?.SafeFireAndForget(_continueOnCapturedContext, _onException);
88+
else
89+
throw new InvalidCommandParameterException(typeof(T), parameter.GetType());
10390
}
10491
#endregion
10592
}
@@ -125,9 +112,9 @@ public sealed class AsyncCommand : IAsyncCommand
125112
/// <param name="onException">If an exception is thrown in the Task, <c>onException</c> will execute. If onException is null, the exception will be re-thrown</param>
126113
/// <param name="canExecute">The Function that verifies whether or not AsyncCommand should execute.</param>
127114
public AsyncCommand(Func<Task> execute,
128-
bool continueOnCapturedContext = true,
115+
Func<object, bool> canExecute = null,
129116
Action<Exception> onException = null,
130-
Func<object, bool> canExecute = null)
117+
bool continueOnCapturedContext = true)
131118
{
132119
_execute = execute;
133120
_continueOnCapturedContext = continueOnCapturedContext;

Src/AsyncAwaitBestPractices.MVVM/InvalidCommandParameterException.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public InvalidCommandParameterException(string message) : base(message)
2929
/// <summary>
3030
/// Initializes a new instance of the <see cref="T:TaskExtensions.MVVM.InvalidCommandParameterException"/> class.
3131
/// </summary>
32-
public InvalidCommandParameterException() : base()
32+
public InvalidCommandParameterException()
3333
{
3434

3535
}

Src/AsyncAwaitBestPractices.UnitTests/Tests_AsyncCommand.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ public async Task AsyncCommand_ExecuteAsync_InvalidReferenceTypeParameter_Test()
9090
public async Task AsyncCommand_ExecuteAsync_NoParameter_ContinueOnCapturedContext_Test(bool continueOnCapturedContext)
9191
{
9292
//Arrange
93-
AsyncCommand command = new AsyncCommand(NoParameterTask, continueOnCapturedContext);
93+
AsyncCommand command = new AsyncCommand(NoParameterTask, continueOnCapturedContext: continueOnCapturedContext);
9494
var callingThreadId = Thread.CurrentThread.ManagedThreadId;
9595

9696
//Act
@@ -107,7 +107,7 @@ public async Task AsyncCommand_ExecuteAsync_NoParameter_ContinueOnCapturedContex
107107
public async Task AsyncCommand_ExecuteAsync_Parameter_ContinueOnCapturedContext_Test(int parameter, bool continueOnCapturedContext)
108108
{
109109
//Arrange
110-
AsyncCommand<int> command = new AsyncCommand<int>(IntParameterTask, continueOnCapturedContext);
110+
AsyncCommand<int> command = new AsyncCommand<int>(IntParameterTask, continueOnCapturedContext: continueOnCapturedContext);
111111
var callingThreadId = Thread.CurrentThread.ManagedThreadId;
112112

113113
//Act
@@ -123,7 +123,7 @@ public async Task AsyncCommand_ExecuteAsync_Parameter_ContinueOnCapturedContext_
123123
public void AsyncCommand_Parameter_CanExecuteTrue_Test()
124124
{
125125
//Arrange
126-
AsyncCommand<int> command = new AsyncCommand<int>(IntParameterTask, canExecute: CanExecuteTrue);
126+
AsyncCommand<int> command = new AsyncCommand<int>(IntParameterTask, CanExecuteTrue);
127127

128128
//Act
129129

Src/AsyncAwaitBestPractices.UnitTests/Tests_IAsyncCommand.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ public async Task AsyncCommand_ExecuteAsync_InvalidReferenceTypeParameter_Test()
9090
public async Task IAsyncCommand_ExecuteAsync_NoParameter_ContinueOnCapturedContext_Test(bool continueOnCapturedContext)
9191
{
9292
//Arrange
93-
IAsyncCommand command = new AsyncCommand(NoParameterTask, continueOnCapturedContext);
93+
IAsyncCommand command = new AsyncCommand(NoParameterTask, continueOnCapturedContext: continueOnCapturedContext);
9494
var callingThreadId = Thread.CurrentThread.ManagedThreadId;
9595

9696
//Act
@@ -107,7 +107,7 @@ public async Task IAsyncCommand_ExecuteAsync_NoParameter_ContinueOnCapturedConte
107107
public async Task IAsyncCommand_ExecuteAsync_Parameter_ContinueOnCapturedContext_Test(object parameter, bool continueOnCapturedContext)
108108
{
109109
//Arrange
110-
IAsyncCommand command = new AsyncCommand<int>(IntParameterTask, continueOnCapturedContext);
110+
IAsyncCommand command = new AsyncCommand<int>(IntParameterTask, continueOnCapturedContext: continueOnCapturedContext);
111111
var callingThreadId = Thread.CurrentThread.ManagedThreadId;
112112

113113
//Act
@@ -123,7 +123,7 @@ public async Task IAsyncCommand_ExecuteAsync_Parameter_ContinueOnCapturedContext
123123
public void IAsyncCommand_Parameter_CanExecuteTrue_Test()
124124
{
125125
//Arrange
126-
IAsyncCommand command = new AsyncCommand<int>(IntParameterTask, canExecute: CanExecuteTrue);
126+
IAsyncCommand command = new AsyncCommand<int>(IntParameterTask, CanExecuteTrue);
127127

128128
//Act
129129

Src/AsyncAwaitBestPractices.nuspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
33
<metadata minClientVersion="2.5">
44
<id>AsyncAwaitBestPractices</id>
5-
<version>0.9.0</version>
5+
<version>1.0.0</version>
66
<title>Task Extensions for System.Threading.Tasks</title>
77
<authors>Brandon Minnick, John Thiriet</authors>
88
<owners>Brandon Minnick</owners>

Src/AsyncAwaitBestPractices/TaskExtensions.cs

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,10 @@ public static async void SafeFireAndForget(this System.Threading.Tasks.Task task
2121
}
2222
catch (System.Exception ex)
2323
{
24-
switch (onException)
25-
{
26-
case null:
27-
throw;
24+
if (onException is null)
25+
throw;
2826

29-
default:
30-
onException?.Invoke(ex);
31-
break;
32-
}
27+
onException?.Invoke(ex);
3328
}
3429
}
3530
}

Src/HackNews.Droid/HackerNews.Droid.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
<OutputType>Library</OutputType>
1010
<RootNamespace>HackerNews.Droid</RootNamespace>
1111
<AssemblyName>HackerNews.Droid</AssemblyName>
12-
<TargetFrameworkVersion>v8.1</TargetFrameworkVersion>
12+
<TargetFrameworkVersion>v9.0</TargetFrameworkVersion>
1313
<AndroidApplication>True</AndroidApplication>
1414
<AndroidResgenFile>Resources\Resource.designer.cs</AndroidResgenFile>
1515
<AndroidResgenClass>Resource</AndroidResgenClass>
@@ -30,7 +30,7 @@
3030
<AndroidHttpClientHandlerType>Xamarin.Android.Net.AndroidClientHandler</AndroidHttpClientHandlerType>
3131
<AndroidTlsProvider>btls</AndroidTlsProvider>
3232
<EmbedAssembliesIntoApk>true</EmbedAssembliesIntoApk>
33-
<AndroidSupportedAbis>armeabi-v7a;armeabi;x86;arm64-v8a;x86_64</AndroidSupportedAbis>
33+
<AndroidSupportedAbis>armeabi-v7a;x86;arm64-v8a;x86_64</AndroidSupportedAbis>
3434
</PropertyGroup>
3535
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
3636
<DebugSymbols>true</DebugSymbols>
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.minnick.HackerNews">
3-
<uses-sdk android:minSdkVersion="15" android:targetSdkVersion="27" />
3+
<uses-sdk android:minSdkVersion="15" android:targetSdkVersion="28" />
44
<application android:label="HackerNews"></application>
55
</manifest>

0 commit comments

Comments
 (0)