diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Execution/TestMethodInfo.ArgumentResolution.cs b/src/Adapter/MSTestAdapter.PlatformServices/Execution/TestMethodInfo.ArgumentResolution.cs index b643842ce7..3c4f06ebff 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/Execution/TestMethodInfo.ArgumentResolution.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Execution/TestMethodInfo.ArgumentResolution.cs @@ -10,6 +10,9 @@ internal partial class TestMethodInfo internal object?[] ResolveArguments(object?[] arguments) { + // Use the cached ParameterTypes property rather than calling MethodInfo.GetParameters() + // (which allocates a fresh ParameterInfo[] on every call). ResolveArguments only reads the + // array, so sharing the cached instance is safe. ParameterInfo[] parametersInfo = ParameterTypes; int requiredParameterCount = 0; bool hasParamsValue = false; diff --git a/src/TestFramework/TestFramework/Internal/ReflectionTestMethodInfo.cs b/src/TestFramework/TestFramework/Internal/ReflectionTestMethodInfo.cs index c82a4f78c1..2a886356a0 100644 --- a/src/TestFramework/TestFramework/Internal/ReflectionTestMethodInfo.cs +++ b/src/TestFramework/TestFramework/Internal/ReflectionTestMethodInfo.cs @@ -42,6 +42,22 @@ public ReflectionTestMethodInfo(MethodInfo methodInfo, string? displayName) public override MethodImplAttributes GetMethodImplementationFlags() => _methodInfo.GetMethodImplementationFlags(); + /// + /// Returns the parameters of the wrapped method, caching the array across calls. + /// + /// The cached array of the wrapped method. + /// + /// MethodInfo.GetParameters() allocates a fresh array on + /// every call (a CLR safety guarantee). The wrapped is immutable, so the + /// array is cached and shared across callers of this wrapper (e.g. display-name computation for every + /// data-driven row) to avoid that per-call allocation. + /// + /// Because the same instance is handed out to every caller, the returned array MUST be treated as + /// read-only. Mutating it (including callers such as user-provided + /// ITestDataSource.GetDisplayName implementations) would corrupt the cache for all subsequent + /// callers. + /// + /// public override ParameterInfo[] GetParameters() => _parameters ??= _methodInfo.GetParameters(); public override object? Invoke(object? obj, BindingFlags invokeAttr, Binder? binder, object?[]? parameters, CultureInfo? culture) => _methodInfo.Invoke(obj, invokeAttr, binder, parameters, culture);