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 using System; 6 using System.Text; 7 using System.Reflection; 8 using System.Diagnostics; 9 using System.Collections.Generic; 10 using System.Reflection.Runtime.General; 11 using System.Reflection.Runtime.TypeInfos; 12 using System.Reflection.Runtime.ParameterInfos; 13 14 using Internal.Reflection.Core; 15 using Internal.Reflection.Core.Execution; 16 17 namespace System.Reflection.Runtime.MethodInfos 18 { 19 internal static class RuntimeMethodHelpers 20 { 21 // 22 // Returns the ParameterInfo objects for the method parameters and return parameter. 23 // 24 // The ParameterInfo objects will report "contextMethod" as their Member property and use it to get type variable information from 25 // the contextMethod's declaring type. The actual metadata, however, comes from "this." 26 // 27 // The methodTypeArguments provides the fill-ins for any method type variable elements in the parameter type signatures. 28 // 29 // Does not array-copy. 30 // 31 internal static RuntimeParameterInfo[] GetRuntimeParameters<TRuntimeMethodCommon>(ref TRuntimeMethodCommon runtimeMethodCommon, MethodBase contextMethod, RuntimeTypeInfo[] methodTypeArguments, out RuntimeParameterInfo returnParameter) 32 where TRuntimeMethodCommon : IRuntimeMethodCommon<TRuntimeMethodCommon>, IEquatable<TRuntimeMethodCommon> 33 { 34 TypeContext typeContext = contextMethod.DeclaringType.CastToRuntimeTypeInfo().TypeContext; 35 typeContext = new TypeContext(typeContext.GenericTypeArguments, methodTypeArguments); 36 QSignatureTypeHandle[] typeSignatures = runtimeMethodCommon.QualifiedMethodSignature; 37 int count = typeSignatures.Length; 38 39 VirtualRuntimeParameterInfoArray result = new VirtualRuntimeParameterInfoArray(count); 40 runtimeMethodCommon.FillInMetadataDescribedParameters(ref result, typeSignatures, contextMethod, typeContext); 41 42 for (int i = 0; i < count; i++) 43 { 44 if (result[i] == null) 45 { 46 result[i] = 47 RuntimeThinMethodParameterInfo.GetRuntimeThinMethodParameterInfo( 48 contextMethod, 49 i - 1, 50 typeSignatures[i], 51 typeContext); 52 } 53 } 54 55 returnParameter = result.First; 56 return result.Remainder; 57 } 58 59 // Compute the ToString() value in a pay-to-play-safe way. 60 internal static string ComputeToString<TRuntimeMethodCommon>(ref TRuntimeMethodCommon runtimeMethodCommon, MethodBase contextMethod, RuntimeTypeInfo[] methodTypeArguments) 61 where TRuntimeMethodCommon : IRuntimeMethodCommon<TRuntimeMethodCommon>, IEquatable<TRuntimeMethodCommon> 62 { 63 RuntimeParameterInfo returnParameter; 64 RuntimeParameterInfo[] parameters = GetRuntimeParameters(ref runtimeMethodCommon, contextMethod, methodTypeArguments, out returnParameter); 65 return ComputeToString(contextMethod, methodTypeArguments, parameters, returnParameter); 66 } 67 68 // Used by method and property ToString() methods to display the list of parameter types. Replicates the behavior of MethodBase.ConstructParameters() 69 // but in a pay-to-play-safe way. ComputeParametersString(RuntimeParameterInfo[] parameters)70 internal static String ComputeParametersString(RuntimeParameterInfo[] parameters) 71 { 72 StringBuilder sb = new StringBuilder(30); 73 for (int i = 0; i < parameters.Length; i++) 74 { 75 if (i != 0) 76 sb.Append(", "); 77 String parameterTypeString = parameters[i].ParameterTypeString; 78 79 // Legacy: Why use "ByRef" for by ref parameters? What language is this? 80 // VB uses "ByRef" but it should precede (not follow) the parameter name. 81 // Why don't we just use "&"? 82 if (parameterTypeString.EndsWith("&")) 83 parameterTypeString = parameterTypeString.Substring(0, parameterTypeString.Length - 1) + " ByRef"; 84 sb.Append(parameterTypeString); 85 } 86 return sb.ToString(); 87 } 88 ComputeToString(MethodBase contextMethod, RuntimeTypeInfo[] methodTypeArguments, RuntimeParameterInfo[] parameters, RuntimeParameterInfo returnParameter)89 internal static String ComputeToString(MethodBase contextMethod, RuntimeTypeInfo[] methodTypeArguments, RuntimeParameterInfo[] parameters, RuntimeParameterInfo returnParameter) 90 { 91 StringBuilder sb = new StringBuilder(30); 92 sb.Append(returnParameter == null ? "Void" : returnParameter.ParameterTypeString); // ConstructorInfos allowed to pass in null rather than craft a ReturnParameterInfo that's always of type void. 93 sb.Append(' '); 94 sb.Append(contextMethod.Name); 95 if (methodTypeArguments.Length != 0) 96 { 97 String sep = ""; 98 sb.Append('['); 99 foreach (RuntimeTypeInfo methodTypeArgument in methodTypeArguments) 100 { 101 sb.Append(sep); 102 sep = ","; 103 String name = methodTypeArgument.InternalNameIfAvailable; 104 if (name == null) 105 name = Type.DefaultTypeNameWhenMissingMetadata; 106 sb.Append(methodTypeArgument.Name); 107 } 108 sb.Append(']'); 109 } 110 sb.Append('('); 111 sb.Append(ComputeParametersString(parameters)); 112 sb.Append(')'); 113 114 return sb.ToString(); 115 } 116 } 117 } 118