@@ -91,8 +91,17 @@ internal static bool HasCorrectTestMethodSignature(this MethodInfo method, bool
91
91
/// <returns>True if the method has a void/task return type..</returns>
92
92
internal static bool IsValidReturnType ( this MethodInfo method , ReflectHelper ? reflectHelper = null )
93
93
=> ReflectHelper . MatchReturnType ( method , typeof ( Task ) )
94
- || ReflectHelper . MatchReturnType ( method , typeof ( ValueTask ) )
95
- || ( ReflectHelper . MatchReturnType ( method , typeof ( void ) ) && method . GetAsyncTypeName ( reflectHelper ) == null ) ;
94
+ || ( ReflectHelper . MatchReturnType ( method , typeof ( void ) ) && method . GetAsyncTypeName ( reflectHelper ) == null )
95
+ // Keep this the last check, as it avoids loading System.Threading.Tasks.Extensions unnecessarily.
96
+ || method . IsValueTask ( ) ;
97
+
98
+ // Avoid loading System.Threading.Tasks.Extensions if not needed.
99
+ // Note: .NET runtime will load all types once it's entering the method.
100
+ // So, moving this out of the method will load System.Threading.Tasks.Extensions
101
+ // Even when invokeResult is null or Task.
102
+ [ MethodImpl ( MethodImplOptions . NoInlining ) ]
103
+ private static bool IsValueTask ( this MethodInfo method )
104
+ => ReflectHelper . MatchReturnType ( method , typeof ( ValueTask ) ) ;
96
105
97
106
/// <summary>
98
107
/// For async methods compiler generates different type and method.
@@ -107,7 +116,7 @@ internal static bool IsValidReturnType(this MethodInfo method, ReflectHelper? re
107
116
return asyncStateMachineAttribute ? . StateMachineType ? . FullName ;
108
117
}
109
118
110
- internal static object ? GetInvokeResult ( this MethodInfo methodInfo , object ? classInstance , params object ? [ ] ? arguments )
119
+ internal static Task ? GetInvokeResultAsync ( this MethodInfo methodInfo , object ? classInstance , params object ? [ ] ? arguments )
111
120
{
112
121
ParameterInfo [ ] ? methodParameters = methodInfo . GetParameters ( ) ;
113
122
@@ -172,9 +181,22 @@ internal static bool IsValidReturnType(this MethodInfo method, ReflectHelper? re
172
181
}
173
182
}
174
183
175
- return invokeResult ;
184
+ return invokeResult switch
185
+ {
186
+ null => null ,
187
+ Task t => t ,
188
+ _ => TryGetTaskFromValueTaskAsync ( invokeResult ) ,
189
+ } ;
176
190
}
177
191
192
+ // Avoid loading System.Threading.Tasks.Extensions if not needed.
193
+ // Note: .NET runtime will load all types once it's entering the method.
194
+ // So, moving this out of the method will load System.Threading.Tasks.Extensions
195
+ // Even when invokeResult is null or Task.
196
+ [ MethodImpl ( MethodImplOptions . NoInlining ) ]
197
+ private static Task ? TryGetTaskFromValueTaskAsync ( object invokeResult )
198
+ => ( invokeResult as ValueTask ? ) ? . AsTask ( ) ;
199
+
178
200
/// <summary>
179
201
/// Invoke a <see cref="MethodInfo"/> as a synchronous <see cref="Task"/>.
180
202
/// </summary>
@@ -189,17 +211,8 @@ internal static bool IsValidReturnType(this MethodInfo method, ReflectHelper? re
189
211
/// </param>
190
212
internal static void InvokeAsSynchronousTask ( this MethodInfo methodInfo , object ? classInstance , params object ? [ ] ? arguments )
191
213
{
192
- object ? invokeResult = methodInfo . GetInvokeResult ( classInstance , arguments ) ;
193
-
194
- // If methodInfo is an async method, wait for returned task
195
- if ( invokeResult is Task task )
196
- {
197
- task . GetAwaiter ( ) . GetResult ( ) ;
198
- }
199
- else if ( invokeResult is ValueTask valueTask )
200
- {
201
- valueTask . GetAwaiter ( ) . GetResult ( ) ;
202
- }
214
+ Task ? invokeResult = methodInfo . GetInvokeResultAsync ( classInstance , arguments ) ;
215
+ invokeResult ? . GetAwaiter ( ) . GetResult ( ) ;
203
216
}
204
217
205
218
private static void InferGenerics ( Type parameterType , Type argumentType , List < ( Type ParameterType , Type Substitution ) > result )
0 commit comments