diff options
author | Atsushi Kanamori <AtsushiKan@users.noreply.github.com> | 2017-08-31 00:08:32 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-08-31 00:08:32 +0300 |
commit | ab453715f6ec1c8e3533061527a3fbd3eed167d4 (patch) | |
tree | 432def6c1f5f49bb3c3cb757c1998edf0551e4ac /src/System.Private.Reflection.Core | |
parent | 37c57b983fbdcc89214e1cf1f5d2b634f166eb8c (diff) |
Update Type.GetMethods() to be generics friendly. (#4420)
The complete specs and rationale are in the
top comment of
https://github.com/dotnet/corefx/issues/16567
but the short version is:
- New Type.GetMethod() overloads with a "genericParameterCount"
parameter. Only considers methods with that number of generic
parameters.
- New api: Type.MakeGenericMethodParameter(int position)
Create a Type representing an unbound generic method parameter
(just an index, no constraints or container information.)
Without this, GetMethod() isn't very useable for searching
for generic methods.
- New api: Type.IsSignatureType
Indicates whether a Type object was created by
MakeGenericMethodParameter() or constructed from
one via MakeArrayType, MakeByRefType, etc.
Sample usage:
class Horror
{
public void Moo(int x, int[] y) {}
public void Moo<T>(T x, T[] y) {}
public void Moo<T>(int x, int[] y) {}
public void Moo<T,U>(T x, U[] y) {} // <-- We want this one.
public void Moo<T,U>(int x, int[] y) {}
}
Type horror = typeof(Horror);
Type theT = Type.MakeGenericMethodParameter(0);
Type theU = Type.MakeGenericMethodParameter(1);
MethodInfo moo = horror.GetMethod("Moo", genericParameterCount: 2, new Type[] { theT, theU.MakeArrayType() });
Diffstat (limited to 'src/System.Private.Reflection.Core')
12 files changed, 51 insertions, 19 deletions
diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/BindingFlagSupport/Shared.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/BindingFlagSupport/Shared.cs index c92b8e729..d8abe89fc 100644 --- a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/BindingFlagSupport/Shared.cs +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/BindingFlagSupport/Shared.cs @@ -128,7 +128,7 @@ namespace System.Reflection.Runtime.BindingFlagSupport for (int i = 0; i < parameterInfos.Length; i++) { // a null argument type implies a null arg which is always a perfect match - if ((object)argumentTypes[i] != null && !parameterInfos[i].ParameterType.Equals(argumentTypes[i])) + if ((object)argumentTypes[i] != null && !argumentTypes[i].MatchesParameterTypeExactly(parameterInfos[i])) return false; } } diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/NonOverriddenApis.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/NonOverriddenApis.cs index 849d1fae9..2e5af22b9 100644 --- a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/NonOverriddenApis.cs +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/NonOverriddenApis.cs @@ -147,6 +147,7 @@ namespace System.Reflection.Runtime.TypeInfos public sealed override bool IsInstanceOfType(object o) => base.IsInstanceOfType(o); public sealed override bool IsSerializable => base.IsSerializable; public sealed override bool IsEquivalentTo(Type other) => base.IsEquivalentTo(other); // Note: If we enable COM type equivalence, this is no longer the correct implementation. + public sealed override bool IsSignatureType => base.IsSignatureType; public sealed override IEnumerable<ConstructorInfo> DeclaredConstructors => base.DeclaredConstructors; public sealed override IEnumerable<EventInfo> DeclaredEvents => base.DeclaredEvents; diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/EcmaFormat/EcmaFormatMethodCommon.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/EcmaFormat/EcmaFormatMethodCommon.cs index 8249cc3c7..e44ba9459 100644 --- a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/EcmaFormat/EcmaFormatMethodCommon.cs +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/EcmaFormat/EcmaFormatMethodCommon.cs @@ -31,13 +31,7 @@ namespace System.Reflection.Runtime.MethodInfos.EcmaFormat // internal struct EcmaFormatMethodCommon : IRuntimeMethodCommon<EcmaFormatMethodCommon>, IEquatable<EcmaFormatMethodCommon> { - public bool IsGenericMethodDefinition - { - get - { - return _method.GetGenericParameters().Count > 0; - } - } + public bool IsGenericMethodDefinition => GenericParameterCount != 0; public MethodInvoker GetUncachedMethodInvoker(RuntimeTypeInfo[] methodArguments, MemberInfo exceptionPertainant) { @@ -77,6 +71,8 @@ namespace System.Reflection.Runtime.MethodInfos.EcmaFormat } } + public int GenericParameterCount => _method.GetGenericParameters().Count; + public RuntimeTypeInfo[] GetGenericTypeParametersWithSpecifiedOwningMethod(RuntimeNamedMethodInfo<EcmaFormatMethodCommon> owningMethod) { GenericParameterHandleCollection genericParameters = _method.GetGenericParameters(); diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/IRuntimeMethodCommon.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/IRuntimeMethodCommon.cs index cba285542..df1de5e97 100644 --- a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/IRuntimeMethodCommon.cs +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/IRuntimeMethodCommon.cs @@ -49,6 +49,7 @@ namespace System.Reflection.Runtime.MethodInfos MethodInvoker GetUncachedMethodInvoker(RuntimeTypeInfo[] methodArguments, MemberInfo exceptionPertainant); bool IsGenericMethodDefinition { get; } + int GenericParameterCount { get; } bool HasSameMetadataDefinitionAs(TRuntimeMethodCommon other); diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/NativeFormat/NativeFormatMethodCommon.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/NativeFormat/NativeFormatMethodCommon.cs index e44cf627b..ba7d93981 100644 --- a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/NativeFormat/NativeFormatMethodCommon.cs +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/NativeFormat/NativeFormatMethodCommon.cs @@ -28,14 +28,7 @@ namespace System.Reflection.Runtime.MethodInfos.NativeFormat // internal struct NativeFormatMethodCommon : IRuntimeMethodCommon<NativeFormatMethodCommon>, IEquatable<NativeFormatMethodCommon> { - public bool IsGenericMethodDefinition - { - get - { - Method method = MethodHandle.GetMethod(Reader); - return method.GenericParameters.GetEnumerator().MoveNext(); - } - } + public bool IsGenericMethodDefinition => GenericParameterCount != 0; public MethodInvoker GetUncachedMethodInvoker(RuntimeTypeInfo[] methodArguments, MemberInfo exceptionPertainant) { @@ -85,6 +78,8 @@ namespace System.Reflection.Runtime.MethodInfos.NativeFormat } } + public int GenericParameterCount => MethodHandle.GetMethod(Reader).GenericParameters.Count; + public RuntimeTypeInfo[] GetGenericTypeParametersWithSpecifiedOwningMethod(RuntimeNamedMethodInfo<NativeFormatMethodCommon> owningMethod) { Method method = MethodHandle.GetMethod(Reader); diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeConstructedGenericMethodInfo.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeConstructedGenericMethodInfo.cs index cbab726c4..6819af1d7 100644 --- a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeConstructedGenericMethodInfo.cs +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeConstructedGenericMethodInfo.cs @@ -76,6 +76,8 @@ namespace System.Reflection.Runtime.MethodInfos return _genericMethodDefinition.GetHashCode(); } + public sealed override int GenericParameterCount => _genericMethodDefinition.GenericParameterCount; + public sealed override MethodInfo GetGenericMethodDefinition() { return _genericMethodDefinition; diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeDummyMethodInfo.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeDummyMethodInfo.cs index 1423d21f7..f841945f6 100644 --- a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeDummyMethodInfo.cs +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeDummyMethodInfo.cs @@ -29,6 +29,7 @@ namespace System.Reflection.Runtime.MethodInfos public sealed override bool IsConstructedGenericMethod { get { throw NotImplemented.ByDesign; } } public sealed override bool IsGenericMethod { get { throw NotImplemented.ByDesign; } } public sealed override bool IsGenericMethodDefinition { get { throw NotImplemented.ByDesign; } } + public sealed override int GenericParameterCount { get { throw NotImplemented.ByDesign; } } public sealed override bool HasSameMetadataDefinitionAs(MemberInfo other) { throw NotImplemented.ByDesign; } public sealed override MethodImplAttributes MethodImplementationFlags { get { throw NotImplemented.ByDesign; } } public sealed override Module Module { get { throw NotImplemented.ByDesign; } } diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeMethodInfo.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeMethodInfo.cs index c3a3bba32..d285ab069 100644 --- a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeMethodInfo.cs +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeMethodInfo.cs @@ -149,6 +149,8 @@ namespace System.Reflection.Runtime.MethodInfos return RuntimeGenericArgumentsOrParameters.CloneTypeArray(); } + public abstract override int GenericParameterCount { get; } + public abstract override MethodInfo GetGenericMethodDefinition(); public sealed override MethodBody GetMethodBody() diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeNamedMethodInfo.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeNamedMethodInfo.cs index d276fa34e..40df076c1 100644 --- a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeNamedMethodInfo.cs +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeNamedMethodInfo.cs @@ -115,6 +115,8 @@ namespace System.Reflection.Runtime.MethodInfos } } + public sealed override int GenericParameterCount => _common.GenericParameterCount; + public sealed override MethodInfo MakeGenericMethod(params Type[] typeArguments) { #if ENABLE_REFLECTION_TRACE diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeSyntheticMethodInfo.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeSyntheticMethodInfo.cs index b4c30e740..e439b4501 100644 --- a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeSyntheticMethodInfo.cs +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeSyntheticMethodInfo.cs @@ -109,6 +109,8 @@ namespace System.Reflection.Runtime.MethodInfos } } + public sealed override int GenericParameterCount => 0; + public sealed override MethodInfo MakeGenericMethod(params Type[] typeArguments) { throw new InvalidOperationException(SR.Format(SR.Arg_NotGenericMethodDefinition, this)); diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.BindingFlags.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.BindingFlags.cs index a5b162518..25cc02987 100644 --- a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.BindingFlags.cs +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.BindingFlags.cs @@ -55,12 +55,23 @@ namespace System.Reflection.Runtime.TypeInfos protected sealed override MethodInfo GetMethodImpl(string name, BindingFlags bindingAttr, Binder binder, CallingConventions callConvention, Type[] types, ParameterModifier[] modifiers) { + return GetMethodImplCommon(name, GenericParameterCountAny, bindingAttr, binder, callConvention, types, modifiers); + } + + protected sealed override MethodInfo GetMethodImpl(string name, int genericParameterCount, BindingFlags bindingAttr, Binder binder, CallingConventions callConvention, Type[] types, ParameterModifier[] modifiers) + { + return GetMethodImplCommon(name, genericParameterCount, bindingAttr, binder, callConvention, types, modifiers); + } + + private MethodInfo GetMethodImplCommon(string name, int genericParameterCount, BindingFlags bindingAttr, Binder binder, CallingConventions callConvention, Type[] types, ParameterModifier[] modifiers) + { Debug.Assert(name != null); // GetMethodImpl() is a funnel for two groups of api. We can distinguish by comparing "types" to null. if (types == null) { // Group #1: This group of api accept only a name and BindingFlags. The other parameters are hard-wired by the non-virtual api entrypoints. + Debug.Assert(genericParameterCount == GenericParameterCountAny); Debug.Assert(binder == null); Debug.Assert(callConvention == CallingConventions.Any); Debug.Assert(modifiers == null); @@ -73,6 +84,8 @@ namespace System.Reflection.Runtime.TypeInfos ListBuilder<MethodInfo> candidates = new ListBuilder<MethodInfo>(); foreach (MethodInfo candidate in queryResult) { + if (genericParameterCount != GenericParameterCountAny && genericParameterCount != candidate.GenericParameterCount) + continue; if (candidate.QualifiesBasedOnParameterCount(bindingAttr, callConvention, types)) candidates.Add(candidate); } @@ -186,6 +199,8 @@ namespace System.Reflection.Runtime.TypeInfos private TypeComponentsCache Cache => _lazyCache ?? (_lazyCache = new TypeComponentsCache(this)); private volatile TypeComponentsCache _lazyCache; + + private const int GenericParameterCountAny = -1; } } diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.cs index 9c6270678..3919b5f58 100644 --- a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.cs +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.cs @@ -430,17 +430,33 @@ namespace System.Reflection.Runtime.TypeInfos // In a pay-for-play world, this can cause needless MissingMetadataExceptions. There is no harm in creating // the Type object for an inconsistent generic type - no EEType will ever match it so any attempt to "invoke" it // will throw an exception. + bool foundSignatureType = false; RuntimeTypeInfo[] runtimeTypeArguments = new RuntimeTypeInfo[typeArguments.Length]; for (int i = 0; i < typeArguments.Length; i++) { - RuntimeTypeInfo runtimeTypeArgument = typeArguments[i] as RuntimeTypeInfo; + RuntimeTypeInfo runtimeTypeArgument = runtimeTypeArguments[i] = typeArguments[i] as RuntimeTypeInfo; if (runtimeTypeArgument == null) { if (typeArguments[i] == null) throw new ArgumentNullException(); + + if (typeArguments[i].IsSignatureType) + { + foundSignatureType = true; + } else + { throw new PlatformNotSupportedException(SR.PlatformNotSupported_MakeGenericType); // "PlatformNotSupported" because on desktop, passing in a foreign type is allowed and creates a RefEmit.TypeBuilder + } } + } + + if (foundSignatureType) + return ReflectionAugments.MakeGenericSignatureType(this, typeArguments); + + for (int i = 0; i < typeArguments.Length; i++) + { + RuntimeTypeInfo runtimeTypeArgument = runtimeTypeArguments[i]; // Desktop compatibility: Treat generic type definitions as a constructed generic type using the generic parameters as type arguments. if (runtimeTypeArgument.IsGenericTypeDefinition) @@ -448,9 +464,8 @@ namespace System.Reflection.Runtime.TypeInfos if (runtimeTypeArgument.IsByRefLike) throw new TypeLoadException(SR.CannotUseByRefLikeTypeInInstantiation); - - runtimeTypeArguments[i] = runtimeTypeArgument; } + return this.GetConstructedGenericType(runtimeTypeArguments); } |