| | | 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 | | |
| | | 4 | | using System; |
| | | 5 | | using System.Collections.Generic; |
| | | 6 | | using System.Linq; |
| | | 7 | | using System.Linq.Expressions; |
| | | 8 | | using System.Reflection; |
| | | 9 | | |
| | | 10 | | namespace CoreWCF.Security.NegotiateInternal |
| | | 11 | | { |
| | | 12 | | /// <summary> |
| | | 13 | | /// Helper class to compile a lambda expression to invoke a method that has a |
| | | 14 | | /// span input with reflection. |
| | | 15 | | /// The span input are expected as array type. |
| | | 16 | | /// Example of generated lambda: (object instance, byte[] input) => ((TargetInternalType) instance).TargetMethod((Re |
| | | 17 | | /// </summary> |
| | | 18 | | internal static class LambdaExpressionBuilder |
| | | 19 | | { |
| | 1 | 20 | | private static readonly MethodInfo s_asSpan = typeof(MemoryExtensions) |
| | 1 | 21 | | .GetMethods() |
| | 269 | 22 | | .Single(m => m.Name == "AsSpan" && m.ToString() == "System.Span`1[T] AsSpan[T](T[])"); |
| | | 23 | | |
| | | 24 | | public static LambdaExpression BuildFor(Type targetType, MethodInfo targetMethod) |
| | | 25 | | { |
| | 1 | 26 | | var _callParameters = new List<Expression>(); |
| | 1 | 27 | | var _lambdaParameters = new List<ParameterExpression> |
| | 1 | 28 | | { |
| | 1 | 29 | | Expression.Parameter(typeof(object)) |
| | 1 | 30 | | }; |
| | | 31 | | |
| | | 32 | | void AddParameter(Type parameterType, bool isOut) |
| | | 33 | | { |
| | 2 | 34 | | if (IsSpan(parameterType, out var itemType)) |
| | | 35 | | { |
| | 1 | 36 | | var parameter = Expression.Parameter(itemType.MakeArrayType()); |
| | 1 | 37 | | MethodInfo asSpanMethod = s_asSpan.MakeGenericMethod(itemType); |
| | 1 | 38 | | UnaryExpression span = Expression.Convert( |
| | 1 | 39 | | Expression.Call(asSpanMethod, parameter), |
| | 1 | 40 | | parameterType); |
| | | 41 | | |
| | 1 | 42 | | _callParameters.Add(span); |
| | 1 | 43 | | _lambdaParameters.Add(parameter); |
| | | 44 | | } |
| | | 45 | | else |
| | | 46 | | { |
| | 1 | 47 | | var parameter = Expression.Parameter(parameterType); |
| | 1 | 48 | | _callParameters.Add(parameter); |
| | 1 | 49 | | _lambdaParameters.Add(parameter); |
| | | 50 | | } |
| | 1 | 51 | | } |
| | | 52 | | |
| | 6 | 53 | | foreach (var methodParameter in targetMethod.GetParameters()) |
| | | 54 | | { |
| | 2 | 55 | | AddParameter( |
| | 2 | 56 | | methodParameter.ParameterType, |
| | 2 | 57 | | methodParameter.IsOut); |
| | | 58 | | } |
| | | 59 | | |
| | 1 | 60 | | var instanceParameter = _lambdaParameters[0]; |
| | 1 | 61 | | var typedInstance = Expression.TypeAs(instanceParameter, targetType); |
| | | 62 | | |
| | 1 | 63 | | MethodCallExpression call = Expression.Call( |
| | 1 | 64 | | typedInstance, |
| | 1 | 65 | | targetMethod, |
| | 1 | 66 | | _callParameters); |
| | | 67 | | |
| | 1 | 68 | | return Expression.Lambda(call, _lambdaParameters.AsEnumerable()); |
| | | 69 | | } |
| | | 70 | | |
| | | 71 | | private static bool IsSpan(Type type, out Type itemType) |
| | | 72 | | { |
| | 2 | 73 | | bool isSpan = (type.FullName.StartsWith("System.Span", StringComparison.Ordinal) || type.FullName.StartsWith |
| | 2 | 74 | | && type.GenericTypeArguments.Length == 1; |
| | | 75 | | |
| | 2 | 76 | | if (isSpan) |
| | | 77 | | { |
| | 1 | 78 | | itemType = type.GenericTypeArguments[0]; |
| | | 79 | | } |
| | | 80 | | else |
| | | 81 | | { |
| | 1 | 82 | | itemType = null; |
| | | 83 | | } |
| | | 84 | | |
| | 1 | 85 | | return isSpan; |
| | | 86 | | } |
| | | 87 | | } |
| | | 88 | | } |