Skip to content

Commit a045b55

Browse files
authored
Merge pull request #161 from CommunityToolkit/dev/icommand-attribute-task-t
Allow Task<T>-returns on methods with [ICommand]
2 parents ec1129b + 5067c3d commit a045b55

File tree

3 files changed

+66
-3
lines changed

3 files changed

+66
-3
lines changed

CommunityToolkit.Mvvm.SourceGenerators/Input/ICommandGenerator.Execute.cs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -309,8 +309,9 @@ public static (string FieldName, string PropertyName) GetGeneratedFieldAndProper
309309
{
310310
string propertyName = methodSymbol.Name;
311311

312-
if (methodSymbol.ReturnType.HasFullyQualifiedName("global::System.Threading.Tasks.Task") &&
313-
methodSymbol.Name.EndsWith("Async"))
312+
if (methodSymbol.Name.EndsWith("Async") &&
313+
(methodSymbol.ReturnType.HasFullyQualifiedName("global::System.Threading.Tasks.Task") ||
314+
methodSymbol.ReturnType.InheritsFromFullyQualifiedName("global::System.Threading.Tasks.Task")))
314315
{
315316
propertyName = propertyName.Substring(0, propertyName.Length - "Async".Length);
316317
}
@@ -372,7 +373,9 @@ private static bool TryMapCommandTypesFromMethod(
372373
return true;
373374
}
374375

375-
if (methodSymbol.ReturnType.HasFullyQualifiedName("global::System.Threading.Tasks.Task"))
376+
// Map all Task-returning methods
377+
if (methodSymbol.ReturnType.HasFullyQualifiedName("global::System.Threading.Tasks.Task") ||
378+
methodSymbol.ReturnType.InheritsFromFullyQualifiedName("global::System.Threading.Tasks.Task"))
376379
{
377380
// Map <void, Task> to IAsyncRelayCommand, AsyncRelayCommand, Func<Task>
378381
if (methodSymbol.Parameters.Length == 0)

CommunityToolkit.Mvvm/Input/Attributes/ICommandAttribute.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,15 @@ namespace CommunityToolkit.Mvvm.Input;
5151
/// <code>
5252
/// Task Method();
5353
/// Task Method(CancellationToken);
54+
/// Task&lt;T&gt; Method();
55+
/// Task&lt;T&gt; Method(CancellationToken);
5456
/// </code>
5557
/// Will both generate an <see cref="IAsyncRelayCommand"/> property (using an <see cref="AsyncRelayCommand{T}"/> instance).
5658
/// <code>
5759
/// Task Method(T?);
5860
/// Task Method(T?, CancellationToken);
61+
/// Task&lt;T&gt; Method(T?);
62+
/// Task&lt;T&gt; Method(T?, CancellationToken);
5963
/// </code>
6064
/// Will both generate an <see cref="IAsyncRelayCommand{T}"/> property (using an <see cref="AsyncRelayCommand{T}"/> instance).
6165
/// </para>

tests/CommunityToolkit.Mvvm.UnitTests/Test_ICommandAttribute.cs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,27 @@ public async Task Test_ICommandAttribute_CancelCommands()
441441
Assert.IsTrue(model.Result2 is OperationCanceledException);
442442
}
443443

444+
[TestMethod]
445+
public async Task Test_ICommandAttribute_TaskOfTReturns()
446+
{
447+
GenericTaskCommands model = new();
448+
449+
Task greetCommandTask = model.GreetCommand.ExecuteAsync(null);
450+
Task greetWithTokenTask = model.GreetWithTokenCommand.ExecuteAsync(null);
451+
Task greetWithParamTask = model.GreetWithParamCommand.ExecuteAsync(null);
452+
Task greetWithParamAndCommandTask = model.GreetWithParamAndTokenCommand.ExecuteAsync(null);
453+
454+
Assert.IsInstanceOfType(greetCommandTask, typeof(Task<string>));
455+
Assert.IsInstanceOfType(greetWithTokenTask, typeof(Task<string>));
456+
Assert.IsInstanceOfType(greetWithParamTask, typeof(Task<string>));
457+
Assert.IsInstanceOfType(greetWithParamAndCommandTask, typeof(Task<string>));
458+
459+
Assert.AreEqual("Hello world", await (Task<string>)greetCommandTask);
460+
Assert.AreEqual("Hello world", await (Task<string>)greetWithTokenTask);
461+
Assert.AreEqual("Hello world", await (Task<string>)greetWithParamTask);
462+
Assert.AreEqual("Hello world", await (Task<string>)greetWithParamAndCommandTask);
463+
}
464+
444465
#region Region
445466
public class Region
446467
{
@@ -731,4 +752,39 @@ private async Task DoWorkWithParameterAsync(int number, CancellationToken token)
731752
}
732753
}
733754
}
755+
756+
public partial class GenericTaskCommands
757+
{
758+
[ICommand]
759+
private async Task<string> GreetAsync()
760+
{
761+
await Task.Yield();
762+
763+
return "Hello world";
764+
}
765+
766+
[ICommand]
767+
private async Task<string> GreetWithTokenAsync(CancellationToken token)
768+
{
769+
await Task.Yield();
770+
771+
return "Hello world";
772+
}
773+
774+
[ICommand]
775+
private async Task<string> GreetWithParamAsync(object _)
776+
{
777+
await Task.Yield();
778+
779+
return "Hello world";
780+
}
781+
782+
[ICommand]
783+
private async Task<string> GreetWithParamAndTokenAsync(object _, CancellationToken token)
784+
{
785+
await Task.Yield();
786+
787+
return "Hello world";
788+
}
789+
}
734790
}

0 commit comments

Comments
 (0)