|
| 1 | +// Licensed to the .NET Foundation under one or more agreements. |
| 2 | +// The .NET Foundation licenses this file to you under the MIT license. |
| 3 | +// See the LICENSE file in the project root for more information. |
| 4 | + |
| 5 | +#nullable enable |
| 6 | + |
| 7 | +using System; |
| 8 | +using System.Linq.Expressions; |
| 9 | +using System.Reflection; |
| 10 | +using Microsoft.ML.Runtime; |
| 11 | + |
| 12 | +namespace Microsoft.ML.Internal.Utilities |
| 13 | +{ |
| 14 | + /// <summary> |
| 15 | + /// Represents the <see cref="MethodInfo"/> for a generic function corresponding to <see cref="Func{T1, T2, TResult}"/>, |
| 16 | + /// with the following characteristics: |
| 17 | + /// |
| 18 | + /// <list type="bullet"> |
| 19 | + /// <item><description>The method is an instance method on an object of type <typeparamref name="TTarget"/>.</description></item> |
| 20 | + /// <item><description>Three generic type arguments.</description></item> |
| 21 | + /// <item><description>A return value of <typeparamref name="TResult"/>.</description></item> |
| 22 | + /// </list> |
| 23 | + /// </summary> |
| 24 | + /// <typeparam name="TTarget">The type of the receiver of the instance method.</typeparam> |
| 25 | + /// <typeparam name="T1">The type of the first parameter of the method.</typeparam> |
| 26 | + /// <typeparam name="T2">The type of the second parameter of the method.</typeparam> |
| 27 | + /// <typeparam name="TResult">The type of the return value of the method.</typeparam> |
| 28 | + internal sealed class FuncInstanceMethodInfo3<TTarget, T1, T2, TResult> : FuncMethodInfo3<T1, T2, TResult> |
| 29 | + where TTarget : class |
| 30 | + { |
| 31 | + private static readonly string _targetTypeCheckMessage = $"Should have a target type of '{typeof(TTarget)}'"; |
| 32 | + |
| 33 | + public FuncInstanceMethodInfo3(Func<T1, T2, TResult> function) |
| 34 | + : this(function.Method) |
| 35 | + { |
| 36 | + } |
| 37 | + |
| 38 | + private FuncInstanceMethodInfo3(MethodInfo methodInfo) |
| 39 | + : base(methodInfo) |
| 40 | + { |
| 41 | + Contracts.CheckParam(!GenericMethodDefinition.IsStatic, nameof(methodInfo), "Should be an instance method"); |
| 42 | + Contracts.CheckParam(GenericMethodDefinition.DeclaringType == typeof(TTarget), nameof(methodInfo), _targetTypeCheckMessage); |
| 43 | + } |
| 44 | + |
| 45 | + /// <summary> |
| 46 | + /// Creates a <see cref="FuncInstanceMethodInfo1{TTarget, T1, T2, TResult}"/> representing the <see cref="MethodInfo"/> |
| 47 | + /// for a generic instance method. This helper method allows the instance to be created prior to the creation of |
| 48 | + /// any instances of the target type. The following example shows the creation of an instance representing the |
| 49 | + /// <see cref="object.Equals(object)"/> method: |
| 50 | + /// |
| 51 | + /// <code> |
| 52 | + /// FuncInstanceMethodInfo1<object, object, int>.Create(obj => obj.Equals) |
| 53 | + /// </code> |
| 54 | + /// </summary> |
| 55 | + /// <param name="expression">The expression which creates the delegate for an instance of the target type.</param> |
| 56 | + /// <returns>A <see cref="FuncInstanceMethodInfo1{TTarget, T1, T2, TResult}"/> representing the <see cref="MethodInfo"/> |
| 57 | + /// for the generic instance method.</returns> |
| 58 | + public static FuncInstanceMethodInfo3<TTarget, T1, T2, TResult> Create(Expression<Func<TTarget, Func<T1, T2, TResult>>> expression) |
| 59 | + { |
| 60 | + if (!(expression is { Body: UnaryExpression { Operand: MethodCallExpression methodCallExpression } })) |
| 61 | + { |
| 62 | + throw Contracts.ExceptParam(nameof(expression), "Unexpected expression form"); |
| 63 | + } |
| 64 | + |
| 65 | + // Verify that we are calling MethodInfo.CreateDelegate(Type, object) |
| 66 | + Contracts.CheckParam(methodCallExpression.Method.DeclaringType == typeof(MethodInfo), nameof(expression), "Unexpected expression form"); |
| 67 | + Contracts.CheckParam(methodCallExpression.Method.Name == nameof(MethodInfo.CreateDelegate), nameof(expression), "Unexpected expression form"); |
| 68 | + Contracts.CheckParam(methodCallExpression.Method.GetParameters().Length == 2, nameof(expression), "Unexpected expression form"); |
| 69 | + Contracts.CheckParam(methodCallExpression.Method.GetParameters()[0].ParameterType == typeof(Type), nameof(expression), "Unexpected expression form"); |
| 70 | + Contracts.CheckParam(methodCallExpression.Method.GetParameters()[1].ParameterType == typeof(object), nameof(expression), "Unexpected expression form"); |
| 71 | + |
| 72 | + // Verify that we are creating a delegate of type Func<T, TResult> |
| 73 | + Contracts.CheckParam(methodCallExpression.Arguments.Count == 2, nameof(expression), "Unexpected expression form"); |
| 74 | + Contracts.CheckParam(methodCallExpression.Arguments[0] is ConstantExpression, nameof(expression), "Unexpected expression form"); |
| 75 | + Contracts.CheckParam(((ConstantExpression)methodCallExpression.Arguments[0]).Type == typeof(Type), nameof(expression), "Unexpected expression form"); |
| 76 | + Contracts.CheckParam((Type)((ConstantExpression)methodCallExpression.Arguments[0]).Value == typeof(Func<T1, T2, TResult>), nameof(expression), "Unexpected expression form"); |
| 77 | + Contracts.CheckParam(methodCallExpression.Arguments[1] is ParameterExpression, nameof(expression), "Unexpected expression form"); |
| 78 | + Contracts.CheckParam(methodCallExpression.Arguments[1] == expression.Parameters[0], nameof(expression), "Unexpected expression form"); |
| 79 | + |
| 80 | + // Check the MethodInfo |
| 81 | + Contracts.CheckParam(methodCallExpression.Object is ConstantExpression, nameof(expression), "Unexpected expression form"); |
| 82 | + Contracts.CheckParam(((ConstantExpression)methodCallExpression.Object).Type == typeof(MethodInfo), nameof(expression), "Unexpected expression form"); |
| 83 | + |
| 84 | + var methodInfo = (MethodInfo)((ConstantExpression)methodCallExpression.Object).Value; |
| 85 | + Contracts.CheckParam(expression.Body is UnaryExpression, nameof(expression), "Unexpected expression form"); |
| 86 | + Contracts.CheckParam(((UnaryExpression)expression.Body).Operand is MethodCallExpression, nameof(expression), "Unexpected expression form"); |
| 87 | + |
| 88 | + return new FuncInstanceMethodInfo3<TTarget, T1, T2, TResult>(methodInfo); |
| 89 | + } |
| 90 | + } |
| 91 | +} |
0 commit comments