|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Reflection.Runtime.CustomAttributes;
using System.Reflection.Runtime.General;
using System.Reflection.Runtime.ParameterInfos;
using System.Reflection.Runtime.TypeInfos;
using System.Runtime.InteropServices;
using Internal.Reflection.Core.Execution;
namespace System.Reflection.Runtime.MethodInfos
{
internal abstract class RuntimeNamedMethodInfo : RuntimeMethodInfo
{
protected internal abstract string ComputeToString(RuntimeMethodInfo contextMethod);
internal abstract MethodBaseInvoker GetUncachedMethodInvoker(RuntimeTypeInfo[] methodArguments, MemberInfo exceptionPertainant);
internal abstract RuntimeMethodHandle GetRuntimeMethodHandle(Type[] methodArguments);
}
//
// The runtime's implementation of non-constructor MethodInfo's that represent a method definition.
//
internal sealed partial class RuntimeNamedMethodInfo<TRuntimeMethodCommon> : RuntimeNamedMethodInfo
where TRuntimeMethodCommon : IRuntimeMethodCommon<TRuntimeMethodCommon>, IEquatable<TRuntimeMethodCommon>
{
//
// methodHandle - the "tkMethodDef" that identifies the method.
// definingType - the "tkTypeDef" that defined the method (this is where you get the metadata reader that created methodHandle.)
// contextType - the type that supplies the type context (i.e. substitutions for generic parameters.) Though you
// get your raw information from "definingType", you report "contextType" as your DeclaringType property.
//
// For example:
//
// typeof(Foo<>).GetTypeInfo().DeclaredMembers
//
// The definingType and contextType are both Foo<>
//
// typeof(Foo<int,String>).GetTypeInfo().DeclaredMembers
//
// The definingType is "Foo<,>"
// The contextType is "Foo<int,String>"
//
// We don't report any DeclaredMembers for arrays or generic parameters so those don't apply.
//
private RuntimeNamedMethodInfo(TRuntimeMethodCommon common, RuntimeTypeInfo reflectedType)
: base()
{
_common = common;
_reflectedType = reflectedType;
}
public sealed override MethodAttributes Attributes
{
get
{
return _common.Attributes;
}
}
public sealed override CallingConventions CallingConvention
{
get
{
return _common.CallingConvention;
}
}
public sealed override IEnumerable<CustomAttributeData> CustomAttributes
{
get
{
foreach (CustomAttributeData cad in _common.TrueCustomAttributes)
{
yield return cad;
}
MethodImplAttributes implAttributes = _common.MethodImplementationFlags;
if (0 != (implAttributes & MethodImplAttributes.PreserveSig))
yield return new RuntimePseudoCustomAttributeData(typeof(PreserveSigAttribute), null);
}
}
public sealed override MethodInfo GetGenericMethodDefinition()
{
if (IsGenericMethodDefinition)
return this;
throw new InvalidOperationException();
}
public sealed override bool IsConstructedGenericMethod
{
get
{
return false;
}
}
public sealed override bool IsGenericMethod
{
get
{
return IsGenericMethodDefinition;
}
}
public sealed override bool IsGenericMethodDefinition
{
get
{
return _common.IsGenericMethodDefinition;
}
}
internal sealed override int GenericParameterCount => _common.GenericParameterCount;
[RequiresDynamicCode("The native code for this instantiation might not be available at runtime.")]
[RequiresUnreferencedCode("If some of the generic arguments are annotated (either with DynamicallyAccessedMembersAttribute, or generic constraints), trimming can't validate that the requirements of those annotations are met.")]
public sealed override MethodInfo MakeGenericMethod(params Type[] typeArguments)
{
ArgumentNullException.ThrowIfNull(typeArguments);
if (GenericTypeParameters.Length == 0)
throw new InvalidOperationException(SR.Format(SR.Arg_NotGenericMethodDefinition, this));
RuntimeTypeInfo[] genericTypeArguments = new RuntimeTypeInfo[typeArguments.Length];
for (int i = 0; i < typeArguments.Length; i++)
{
Type typeArgument = typeArguments[i];
if (typeArgument == null)
throw new ArgumentNullException();
if (typeArgument is not RuntimeType typeArgumentAsRuntimeType)
throw new PlatformNotSupportedException(SR.Format(SR.Reflection_CustomReflectionObjectsNotSupported, typeArguments[i]));
if (typeArgumentAsRuntimeType.IsByRefLike)
throw new BadImageFormatException(SR.CannotUseByRefLikeTypeInInstantiation);
genericTypeArguments[i] = typeArgumentAsRuntimeType.GetRuntimeTypeInfo();
}
if (typeArguments.Length != GenericTypeParameters.Length)
throw new ArgumentException(SR.Format(SR.Argument_NotEnoughGenArguments, typeArguments.Length, GenericTypeParameters.Length));
RuntimeMethodInfo methodInfo = (RuntimeMethodInfo)RuntimeConstructedGenericMethodInfo.GetRuntimeConstructedGenericMethodInfo(this, genericTypeArguments);
ReflectionCoreExecution.ExecutionEnvironment.ValidateGenericMethodConstraints(methodInfo);
return methodInfo;
}
internal sealed override MethodBase MetadataDefinitionMethod
{
get
{
return RuntimeNamedMethodInfo<TRuntimeMethodCommon>.GetRuntimeNamedMethodInfo(_common.RuntimeMethodCommonOfUninstantiatedMethod, _common.DefiningTypeInfo);
}
}
public sealed override MethodImplAttributes MethodImplementationFlags
{
get
{
return _common.MethodImplementationFlags;
}
}
public sealed override Module Module
{
get
{
return _common.Module;
}
}
public sealed override Type ReflectedType
{
get
{
return _reflectedType.ToType();
}
}
public sealed override int MetadataToken
{
get
{
return _common.MetadataToken;
}
}
public sealed override string ToString()
{
return ComputeToString(this);
}
public sealed override bool HasSameMetadataDefinitionAs(MemberInfo other)
{
ArgumentNullException.ThrowIfNull(other);
// Do not rewrite as a call to IsConstructedGenericMethod - we haven't yet established that "other" is a runtime-implemented member yet!
if (other is RuntimeConstructedGenericMethodInfo otherConstructedGenericMethod)
other = otherConstructedGenericMethod.GetGenericMethodDefinition();
if (!(other is RuntimeNamedMethodInfo<TRuntimeMethodCommon> otherMethod))
return false;
return _common.HasSameMetadataDefinitionAs(otherMethod._common);
}
public sealed override bool Equals(object obj)
{
if (!(obj is RuntimeNamedMethodInfo<TRuntimeMethodCommon> other))
return false;
if (!_common.Equals(other._common))
return false;
if (!(_reflectedType.Equals(other._reflectedType)))
return false;
return true;
}
public sealed override int GetHashCode()
{
return HashCode.Combine(_common, _reflectedType);
}
public sealed override RuntimeMethodHandle MethodHandle => GetRuntimeMethodHandle(null);
protected internal sealed override string ComputeToString(RuntimeMethodInfo contextMethod)
{
return RuntimeMethodHelpers.ComputeToString(ref _common, contextMethod, contextMethod.RuntimeGenericArgumentsOrParameters);
}
internal sealed override RuntimeTypeInfo[] RuntimeGenericArgumentsOrParameters
{
get
{
return this.GenericTypeParameters;
}
}
internal sealed override RuntimeParameterInfo[] GetRuntimeParameters(RuntimeMethodInfo contextMethod, out RuntimeParameterInfo returnParameter)
{
return RuntimeMethodHelpers.GetRuntimeParameters(ref _common, contextMethod, contextMethod.RuntimeGenericArgumentsOrParameters, out returnParameter);
}
internal sealed override RuntimeTypeInfo RuntimeDeclaringType
{
get
{
return _common.DeclaringType;
}
}
internal sealed override string RuntimeName
{
get
{
return _common.Name;
}
}
internal sealed override RuntimeMethodInfo WithReflectedTypeSetToDeclaringType
{
get
{
if (_reflectedType.Equals(_common.DefiningTypeInfo))
return this;
return RuntimeNamedMethodInfo<TRuntimeMethodCommon>.GetRuntimeNamedMethodInfo(_common, _common.ContextTypeInfo);
}
}
private RuntimeTypeInfo[] GenericTypeParameters
{
get
{
RuntimeNamedMethodInfo<TRuntimeMethodCommon> owningMethod = this;
if (DeclaringType.IsConstructedGenericType)
{
// Desktop compat: Constructed generic types and their generic type definitions share the same Type objects for method generic parameters.
TRuntimeMethodCommon uninstantiatedCommon = _common.RuntimeMethodCommonOfUninstantiatedMethod;
owningMethod = RuntimeNamedMethodInfo<TRuntimeMethodCommon>.GetRuntimeNamedMethodInfo(uninstantiatedCommon, uninstantiatedCommon.DeclaringType);
}
else
{
// Desktop compat: DeclaringMethod always returns a MethodInfo whose ReflectedType is equal to DeclaringType.
if (!_reflectedType.Equals(_common.DeclaringType))
owningMethod = RuntimeNamedMethodInfo<TRuntimeMethodCommon>.GetRuntimeNamedMethodInfo(_common, _common.DeclaringType);
}
return _common.GetGenericTypeParametersWithSpecifiedOwningMethod(owningMethod);
}
}
internal sealed override MethodBaseInvoker GetUncachedMethodInvoker(RuntimeTypeInfo[] methodArguments, MemberInfo exceptionPertainant)
{
MethodBaseInvoker invoker = _common.GetUncachedMethodInvoker(methodArguments, exceptionPertainant, out Exception exception);
if (invoker == null)
throw exception;
return invoker;
}
protected sealed override MethodBaseInvoker UncachedMethodInvoker
{
get
{
MethodBaseInvoker invoker = this.GetCustomMethodInvokerIfNeeded();
if (invoker != null)
return invoker;
return GetUncachedMethodInvoker(GenericTypeParameters, this);
}
}
internal sealed override RuntimeMethodHandle GetRuntimeMethodHandle(Type[] genericArgs)
{
return _common.GetRuntimeMethodHandle(genericArgs);
}
private TRuntimeMethodCommon _common;
private readonly RuntimeTypeInfo _reflectedType;
}
}
|