File: System\Reflection\MethodInvoker.cs
Web Access
Project: src\src\runtime\src\coreclr\nativeaot\System.Private.CoreLib\src\System.Private.CoreLib.csproj (System.Private.CoreLib)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Reflection.Runtime.MethodInfos;

using Internal.Reflection.Core.Execution;

using static System.Reflection.DynamicInvokeInfo;

namespace System.Reflection
{
    public sealed class MethodInvoker
    {
        private readonly MethodBaseInvoker _methodBaseInvoker;
        private readonly int _parameterCount;

        internal MethodInvoker(RuntimeMethodInfo method)
        {
            _methodBaseInvoker = method.MethodInvoker;
            _parameterCount = method.GetParametersAsSpan().Length;
        }

        internal MethodInvoker(RuntimeConstructorInfo constructor)
        {
            _methodBaseInvoker = constructor.MethodInvoker;
        }

        public static MethodInvoker Create(MethodBase method)
        {
            ArgumentNullException.ThrowIfNull(method);

            if (method is RuntimeMethodInfo rmi)
            {
                return new MethodInvoker(rmi);
            }

            if (method is RuntimeConstructorInfo rci)
            {
                // This is useful for calling a constructor on an already-initialized object
                // such as created from RuntimeHelpers.GetUninitializedObject(Type).
                return new MethodInvoker(rci);
            }

            throw new ArgumentException(SR.Argument_MustBeRuntimeMethod, nameof(method));
        }

        [DebuggerGuidedStepThrough]
        public object? Invoke(object? obj)
        {
            if (_parameterCount != 0)
            {
                ThrowForArgCountMismatch();
            }

            object? result = _methodBaseInvoker.InvokeDirectWithFewArgs(obj, default);
            DebugAnnotations.PreviousCallContainsDebuggerStepInCode();
            return result;
        }

        [DebuggerGuidedStepThrough]
        public object? Invoke(object? obj, object? arg1)
        {
            if (_parameterCount != 1)
            {
                ThrowForArgCountMismatch();
            }

            object? result = _methodBaseInvoker.InvokeDirectWithFewArgs(obj, new Span<object?>(ref arg1, _parameterCount));
            DebugAnnotations.PreviousCallContainsDebuggerStepInCode();
            return result;
        }

        [DebuggerGuidedStepThrough]
        public object? Invoke(object? obj, object? arg1, object? arg2)
        {
            if (_parameterCount != 2)
            {
                ThrowForArgCountMismatch();
            }

            StackAllocatedArguments argStorage = default;
            argStorage._args[0] = arg1;
            argStorage._args[1] = arg2;

            object? result = _methodBaseInvoker.InvokeDirectWithFewArgs(obj, ((Span<object?>)argStorage._args).Slice(0, 2));
            DebugAnnotations.PreviousCallContainsDebuggerStepInCode();
            return result;
        }

        [DebuggerGuidedStepThrough]
        public object? Invoke(object? obj, object? arg1, object? arg2, object? arg3)
        {
            if (_parameterCount != 3)
            {
                ThrowForArgCountMismatch();
            }

            StackAllocatedArguments argStorage = default;
            argStorage._args[0] = arg1;
            argStorage._args[1] = arg2;
            argStorage._args[2] = arg3;

            object? result = _methodBaseInvoker.InvokeDirectWithFewArgs(obj, ((Span<object?>)argStorage._args).Slice(0, 3));
            DebugAnnotations.PreviousCallContainsDebuggerStepInCode();
            return result;
        }

        [DebuggerGuidedStepThrough]
        public object? Invoke(object? obj, object? arg1, object? arg2, object? arg3, object? arg4)
        {
            if (_parameterCount != 4)
            {
                ThrowForArgCountMismatch();
            }

            StackAllocatedArguments argStorage = default;
            argStorage._args[0] = arg1;
            argStorage._args[1] = arg2;
            argStorage._args[2] = arg3;
            argStorage._args[3] = arg4;

            object? result = _methodBaseInvoker.InvokeDirectWithFewArgs(obj, ((Span<object?>)argStorage._args).Slice(0, 4));
            DebugAnnotations.PreviousCallContainsDebuggerStepInCode();
            return result;
        }

        [DebuggerGuidedStepThrough]
        public object? Invoke(object? obj, Span<object?> arguments)
        {
            object? result = _methodBaseInvoker.Invoke(obj, arguments);
            DebugAnnotations.PreviousCallContainsDebuggerStepInCode();
            return result;
        }

        [DoesNotReturn]
        private static void ThrowForArgCountMismatch()
        {
            throw new TargetParameterCountException(SR.Arg_ParmCnt);
        }
    }
}