Add Type.GetMemberWithSameMetadataDefinitionAs (#53704)
authorEric Erhardt <eric.erhardt@microsoft.com>
Tue, 15 Jun 2021 21:14:10 +0000 (16:14 -0500)
committerGitHub <noreply@github.com>
Tue, 15 Jun 2021 21:14:10 +0000 (16:14 -0500)
* Add API to find MethodInfo on instantiated generic type from generic type definition

Fix #45771

* Rename to GetMemberWithSameMetadataDefinitionAs
* Fix a bug for NestedType
* Use new method libraries that were working around not having it

* Implement GetMemberWithSameMetadataDefinitionAs in mono

* Revert JavaScript Runtime changes.

* Support inheritance in GetMemberWithSameMetadataDefinitionAs.

19 files changed:
src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs
src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/NullableConverter.cs
src/libraries/System.Linq.Expressions/src/System/Dynamic/Utils/TypeUtils.cs
src/libraries/System.Linq.Expressions/src/System/Linq/Expressions/Compiler/ILGen.cs
src/libraries/System.Linq.Expressions/src/System/Linq/Expressions/Compiler/LambdaCompiler.Binary.cs
src/libraries/System.Linq.Expressions/src/System/Linq/Expressions/Compiler/LambdaCompiler.Expressions.cs
src/libraries/System.Linq.Expressions/src/System/Linq/Expressions/Compiler/LambdaCompiler.Unary.cs
src/libraries/System.Linq.Expressions/src/System/Linq/Expressions/LambdaExpression.cs
src/libraries/System.Private.CoreLib/src/Resources/Strings.resx
src/libraries/System.Private.CoreLib/src/System/Reflection/TypeDelegator.cs
src/libraries/System.Private.CoreLib/src/System/Type.cs
src/libraries/System.Reflection/tests/TypeInfoTests.cs
src/libraries/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/ObjectManager.cs
src/libraries/System.Runtime/ref/System.Runtime.cs
src/mono/System.Private.CoreLib/src/System/Reflection/RuntimeEventInfo.cs
src/mono/System.Private.CoreLib/src/System/Reflection/RuntimeFieldInfo.cs
src/mono/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.cs
src/mono/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs
src/mono/System.Private.CoreLib/src/System/RuntimeType.Mono.cs

index 1e2ece2..b07971e 100644 (file)
@@ -3068,6 +3068,131 @@ namespace System
 
             return compressMembers;
         }
+
+        public override MemberInfo GetMemberWithSameMetadataDefinitionAs(MemberInfo member)
+        {
+            if (member is null) throw new ArgumentNullException(nameof(member));
+
+            RuntimeType? runtimeType = this;
+            while (runtimeType != null)
+            {
+                MemberInfo? result = member.MemberType switch
+                {
+                    MemberTypes.Method => GetMethodWithSameMetadataDefinitionAs(runtimeType, member),
+                    MemberTypes.Constructor => GetConstructorWithSameMetadataDefinitionAs(runtimeType, member),
+                    MemberTypes.Property => GetPropertyWithSameMetadataDefinitionAs(runtimeType, member),
+                    MemberTypes.Field => GetFieldWithSameMetadataDefinitionAs(runtimeType, member),
+                    MemberTypes.Event => GetEventWithSameMetadataDefinitionAs(runtimeType, member),
+                    MemberTypes.NestedType => GetNestedTypeWithSameMetadataDefinitionAs(runtimeType, member),
+                    _ => null
+                };
+
+                if (result != null)
+                {
+                    return result;
+                }
+
+                runtimeType = runtimeType.GetBaseType();
+            }
+
+            throw CreateGetMemberWithSameMetadataDefinitionAsNotFoundException(member);
+        }
+
+        private static MemberInfo? GetMethodWithSameMetadataDefinitionAs(RuntimeType runtimeType, MemberInfo method)
+        {
+            RuntimeMethodInfo[] cache = runtimeType.Cache.GetMethodList(MemberListType.CaseSensitive, method.Name);
+
+            for (int i = 0; i < cache.Length; i++)
+            {
+                RuntimeMethodInfo candidate = cache[i];
+                if (candidate.HasSameMetadataDefinitionAs(method))
+                {
+                    return candidate;
+                }
+            }
+
+            return null;
+        }
+
+        private static MemberInfo? GetConstructorWithSameMetadataDefinitionAs(RuntimeType runtimeType, MemberInfo constructor)
+        {
+            RuntimeConstructorInfo[] cache = runtimeType.Cache.GetConstructorList(MemberListType.CaseSensitive, constructor.Name);
+
+            for (int i = 0; i < cache.Length; i++)
+            {
+                RuntimeConstructorInfo candidate = cache[i];
+                if (candidate.HasSameMetadataDefinitionAs(constructor))
+                {
+                    return candidate;
+                }
+            }
+
+            return null;
+        }
+
+        private static MemberInfo? GetPropertyWithSameMetadataDefinitionAs(RuntimeType runtimeType, MemberInfo property)
+        {
+            RuntimePropertyInfo[] cache = runtimeType.Cache.GetPropertyList(MemberListType.CaseSensitive, property.Name);
+
+            for (int i = 0; i < cache.Length; i++)
+            {
+                RuntimePropertyInfo candidate = cache[i];
+                if (candidate.HasSameMetadataDefinitionAs(property))
+                {
+                    return candidate;
+                }
+            }
+
+            return null;
+        }
+
+        private static MemberInfo? GetFieldWithSameMetadataDefinitionAs(RuntimeType runtimeType, MemberInfo field)
+        {
+            RuntimeFieldInfo[] cache = runtimeType.Cache.GetFieldList(MemberListType.CaseSensitive, field.Name);
+
+            for (int i = 0; i < cache.Length; i++)
+            {
+                RuntimeFieldInfo candidate = cache[i];
+                if (candidate.HasSameMetadataDefinitionAs(field))
+                {
+                    return candidate;
+                }
+            }
+
+            return null;
+        }
+
+        private static MemberInfo? GetEventWithSameMetadataDefinitionAs(RuntimeType runtimeType, MemberInfo eventInfo)
+        {
+            RuntimeEventInfo[] cache = runtimeType.Cache.GetEventList(MemberListType.CaseSensitive, eventInfo.Name);
+
+            for (int i = 0; i < cache.Length; i++)
+            {
+                RuntimeEventInfo candidate = cache[i];
+                if (candidate.HasSameMetadataDefinitionAs(eventInfo))
+                {
+                    return candidate;
+                }
+            }
+
+            return null;
+        }
+
+        private static MemberInfo? GetNestedTypeWithSameMetadataDefinitionAs(RuntimeType runtimeType, MemberInfo nestedType)
+        {
+            RuntimeType[] cache = runtimeType.Cache.GetNestedTypeList(MemberListType.CaseSensitive, nestedType.Name);
+
+            for (int i = 0; i < cache.Length; i++)
+            {
+                RuntimeType candidate = cache[i];
+                if (candidate.HasSameMetadataDefinitionAs(nestedType))
+                {
+                    return candidate;
+                }
+            }
+
+            return null;
+        }
         #endregion
 
         #region Identity
index 9bcfdc0..08a077b 100644 (file)
@@ -15,6 +15,8 @@ namespace System.ComponentModel
     /// </summary>
     public class NullableConverter : TypeConverter
     {
+        private static readonly ConstructorInfo s_nullableConstructor = typeof(Nullable<>).GetConstructor(typeof(Nullable<>).GetGenericArguments())!;
+
         /// <summary>
         /// Nullable converter is initialized with the underlying simple type.
         /// </summary>
@@ -108,7 +110,7 @@ namespace System.ComponentModel
             }
             else if (destinationType == typeof(InstanceDescriptor))
             {
-                ConstructorInfo ci = GetNullableConstructor();
+                ConstructorInfo ci = (ConstructorInfo)NullableType.GetMemberWithSameMetadataDefinitionAs(s_nullableConstructor);
                 Debug.Assert(ci != null, "Couldn't find constructor");
                 return new InstanceDescriptor(ci, new object[] { value }, true);
             }
@@ -128,14 +130,6 @@ namespace System.ComponentModel
             return base.ConvertTo(context, culture, value, destinationType);
         }
 
-        [DynamicDependency(DynamicallyAccessedMemberTypes.PublicConstructors, typeof(Nullable<>))]
-        [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2075:UnrecognizedReflectionPattern",
-            Justification = "The Nullable<T> ctor will be preserved by the DynamicDependency.")]
-        private ConstructorInfo GetNullableConstructor()
-        {
-            return NullableType.GetConstructor(new Type[] { UnderlyingType })!;
-        }
-
         /// <summary>
         /// </summary>
         public override object CreateInstance(ITypeDescriptorContext context, IDictionary propertyValues)
index afa81a1..3a0fc56 100644 (file)
@@ -16,6 +16,8 @@ namespace System.Dynamic.Utils
             .Select(i => i.GetGenericTypeDefinition())
             .ToArray();
 
+        private static readonly ConstructorInfo s_nullableConstructor = typeof(Nullable<>).GetConstructor(typeof(Nullable<>).GetGenericArguments())!;
+
         public static Type GetNonNullableType(this Type type) => IsNullableType(type) ? type.GetGenericArguments()[0] : type;
 
         public static Type GetNullableType(this Type type)
@@ -29,15 +31,11 @@ namespace System.Dynamic.Utils
             return type;
         }
 
-        [DynamicDependency(DynamicallyAccessedMemberTypes.PublicConstructors, typeof(Nullable<>))]
-        [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2070:UnrecognizedReflectionPattern",
-            Justification = "The Nullable<T> ctor will be preserved by the DynamicDependency.")]
-        public static ConstructorInfo GetNullableConstructor(Type nullableType, Type nonNullableType)
+        public static ConstructorInfo GetNullableConstructor(Type nullableType)
         {
             Debug.Assert(nullableType.IsNullableType());
-            Debug.Assert(!nonNullableType.IsNullableType() && nonNullableType.IsValueType);
 
-            return nullableType.GetConstructor(new Type[] { nonNullableType })!;
+            return (ConstructorInfo)nullableType.GetMemberWithSameMetadataDefinitionAs(s_nullableConstructor);
         }
 
         public static bool IsNullableType(this Type type) => type.IsConstructedGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>);
index 673e213..5cd7fd5 100644 (file)
@@ -12,6 +12,10 @@ namespace System.Linq.Expressions.Compiler
 {
     internal static class ILGen
     {
+        private static readonly MethodInfo s_nullableHasValueGetter = typeof(Nullable<>).GetMethod("get_HasValue", BindingFlags.Instance | BindingFlags.Public)!;
+        private static readonly MethodInfo s_nullableValueGetter = typeof(Nullable<>).GetMethod("get_Value", BindingFlags.Instance | BindingFlags.Public)!;
+        private static readonly MethodInfo s_nullableGetValueOrDefault = typeof(Nullable<>).GetMethod("GetValueOrDefault", Type.EmptyTypes)!;
+
         internal static void Emit(this ILGenerator il, OpCode opcode, MethodBase methodBase)
         {
             Debug.Assert(methodBase is MethodInfo || methodBase is ConstructorInfo);
@@ -485,7 +489,7 @@ namespace System.Linq.Expressions.Compiler
 
                 if (TryEmitILConstant(il, value, nonNullType))
                 {
-                    il.Emit(OpCodes.Newobj, TypeUtils.GetNullableConstructor(type, nonNullType));
+                    il.Emit(OpCodes.Newobj, TypeUtils.GetNullableConstructor(type));
                     return true;
                 }
 
@@ -826,7 +830,7 @@ namespace System.Linq.Expressions.Compiler
             Type nnTypeTo = typeTo.GetNonNullableType();
             il.EmitConvertToType(nnTypeFrom, nnTypeTo, isChecked, locals);
             // construct result type
-            ConstructorInfo ci = TypeUtils.GetNullableConstructor(typeTo, nnTypeTo);
+            ConstructorInfo ci = TypeUtils.GetNullableConstructor(typeTo);
             il.Emit(OpCodes.Newobj, ci);
             labEnd = il.DefineLabel();
             il.Emit(OpCodes.Br_S, labEnd);
@@ -846,7 +850,7 @@ namespace System.Linq.Expressions.Compiler
             Debug.Assert(typeTo.IsNullableType());
             Type nnTypeTo = typeTo.GetNonNullableType();
             il.EmitConvertToType(typeFrom, nnTypeTo, isChecked, locals);
-            ConstructorInfo ci = TypeUtils.GetNullableConstructor(typeTo, nnTypeTo);
+            ConstructorInfo ci = TypeUtils.GetNullableConstructor(typeTo);
             il.Emit(OpCodes.Newobj, ci);
         }
 
@@ -898,38 +902,29 @@ namespace System.Linq.Expressions.Compiler
                 il.EmitNonNullableToNullableConversion(typeFrom, typeTo, isChecked, locals);
         }
 
-        [DynamicDependency("get_HasValue", typeof(Nullable<>))]
-        [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2070:UnrecognizedReflectionPattern",
-            Justification = "The Nullable<T> method will be preserved by the DynamicDependency.")]
         internal static void EmitHasValue(this ILGenerator il, Type nullableType)
         {
             Debug.Assert(nullableType.IsNullableType());
 
-            MethodInfo mi = nullableType.GetMethod("get_HasValue", BindingFlags.Instance | BindingFlags.Public)!;
+            MethodInfo mi = (MethodInfo)nullableType.GetMemberWithSameMetadataDefinitionAs(s_nullableHasValueGetter);
             Debug.Assert(nullableType.IsValueType);
             il.Emit(OpCodes.Call, mi);
         }
 
-        [DynamicDependency("get_Value", typeof(Nullable<>))]
-        [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2070:UnrecognizedReflectionPattern",
-            Justification = "The Nullable<T> method will be preserved by the DynamicDependency.")]
         internal static void EmitGetValue(this ILGenerator il, Type nullableType)
         {
             Debug.Assert(nullableType.IsNullableType());
 
-            MethodInfo mi = nullableType.GetMethod("get_Value", BindingFlags.Instance | BindingFlags.Public)!;
+            MethodInfo mi = (MethodInfo)nullableType.GetMemberWithSameMetadataDefinitionAs(s_nullableValueGetter);
             Debug.Assert(nullableType.IsValueType);
             il.Emit(OpCodes.Call, mi);
         }
 
-        [DynamicDependency("GetValueOrDefault()", typeof(Nullable<>))]
-        [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2070:UnrecognizedReflectionPattern",
-            Justification = "The Nullable<T> method will be preserved by the DynamicDependency.")]
         internal static void EmitGetValueOrDefault(this ILGenerator il, Type nullableType)
         {
             Debug.Assert(nullableType.IsNullableType());
 
-            MethodInfo mi = nullableType.GetMethod("GetValueOrDefault", Type.EmptyTypes)!;
+            MethodInfo mi = (MethodInfo)nullableType.GetMemberWithSameMetadataDefinitionAs(s_nullableGetValueOrDefault);
             Debug.Assert(nullableType.IsValueType);
             il.Emit(OpCodes.Call, mi);
         }
index a888be0..c4e448a 100644 (file)
@@ -480,7 +480,7 @@ namespace System.Linq.Expressions.Compiler
             EmitBinaryOperator(op, leftType.GetNonNullableType(), rightType.GetNonNullableType(), resultNonNullableType, liftedToNull: false);
 
             // construct result type
-            ConstructorInfo ci = TypeUtils.GetNullableConstructor(resultType, resultNonNullableType);
+            ConstructorInfo ci = TypeUtils.GetNullableConstructor(resultType);
             _ilg.Emit(OpCodes.Newobj, ci);
             _ilg.Emit(OpCodes.Stloc, locResult);
             _ilg.Emit(OpCodes.Br_S, labEnd);
index a3049f8..505b298 100644 (file)
@@ -4,7 +4,6 @@
 using System.Collections.Generic;
 using System.Collections.ObjectModel;
 using System.Diagnostics;
-using System.Diagnostics.CodeAnalysis;
 using System.Dynamic.Utils;
 using System.Reflection;
 using System.Reflection.Emit;
@@ -14,6 +13,8 @@ namespace System.Linq.Expressions.Compiler
 {
     internal sealed partial class LambdaCompiler
     {
+        private static readonly FieldInfo s_callSiteTargetField = typeof(CallSite<>).GetField("Target")!;
+
         [Flags]
         internal enum CompilationFlags
         {
@@ -613,13 +614,10 @@ namespace System.Linq.Expressions.Compiler
             EmitWriteBack(wb);
         }
 
-        [DynamicDependency("Target", typeof(CallSite<>))]
-        [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2070:UnrecognizedReflectionPattern",
-            Justification = "The 'Target' field will be preserved by the DynamicDependency.")]
         private static FieldInfo GetCallSiteTargetField(Type siteType)
         {
             Debug.Assert(siteType.IsGenericType && siteType.GetGenericTypeDefinition() == typeof(CallSite<>));
-            return siteType.GetField("Target")!;
+            return (FieldInfo)siteType.GetMemberWithSameMetadataDefinitionAs(s_callSiteTargetField);
         }
 
         private void EmitNewExpression(Expression expr)
@@ -1171,7 +1169,7 @@ namespace System.Linq.Expressions.Compiler
                         EmitMethodCallExpression(mc);
                         if (resultType.IsNullableType() && !TypeUtils.AreEquivalent(resultType, mc.Type))
                         {
-                            ConstructorInfo ci = TypeUtils.GetNullableConstructor(resultType, mc.Type);
+                            ConstructorInfo ci = TypeUtils.GetNullableConstructor(resultType);
                             _ilg.Emit(OpCodes.Newobj, ci);
                         }
                         _ilg.Emit(OpCodes.Br_S, exit);
@@ -1275,7 +1273,7 @@ namespace System.Linq.Expressions.Compiler
                         EmitMethodCallExpression(mc);
                         if (resultType.IsNullableType() && !TypeUtils.AreEquivalent(resultType, mc.Type))
                         {
-                            ConstructorInfo ci = TypeUtils.GetNullableConstructor(resultType, mc.Type);
+                            ConstructorInfo ci = TypeUtils.GetNullableConstructor(resultType);
                             _ilg.Emit(OpCodes.Newobj, ci);
                         }
                         _ilg.Emit(OpCodes.Br_S, exit);
index f487d73..b17d414 100644 (file)
@@ -94,7 +94,7 @@ namespace System.Linq.Expressions.Compiler
                     EmitBinaryOperator(ExpressionType.SubtractChecked, nnType, nnType, nnType, liftedToNull: false);
 
                     // construct result
-                    _ilg.Emit(OpCodes.Newobj, TypeUtils.GetNullableConstructor(type, nnType));
+                    _ilg.Emit(OpCodes.Newobj, TypeUtils.GetNullableConstructor(type));
                     _ilg.Emit(OpCodes.Br_S, end);
 
                     // if null then push back on stack
@@ -164,7 +164,7 @@ namespace System.Linq.Expressions.Compiler
                         EmitUnaryOperator(op, nnOperandType, nnOperandType);
 
                         // construct result
-                        ConstructorInfo ci = TypeUtils.GetNullableConstructor(resultType, nnOperandType);
+                        ConstructorInfo ci = TypeUtils.GetNullableConstructor(resultType);
                         _ilg.Emit(OpCodes.Newobj, ci);
                         _ilg.Emit(OpCodes.Br_S, labEnd);
 
index fc45b9c..a615e89 100644 (file)
@@ -21,6 +21,8 @@ namespace System.Linq.Expressions
     [DebuggerTypeProxy(typeof(LambdaExpressionProxy))]
     public abstract class LambdaExpression : Expression, IParameterProvider
     {
+        private static readonly MethodInfo s_expressionCompileMethodInfo = typeof(Expression<>).GetMethod("Compile", Type.EmptyTypes)!;
+
         private readonly Expression _body;
 
         internal LambdaExpression(Expression body)
@@ -119,20 +121,7 @@ namespace System.Linq.Expressions
                 return typeof(LambdaExpression).GetMethod("Compile", Type.EmptyTypes)!;
             }
 
-            return GetDerivedCompileMethod(lambdaExpressionType);
-        }
-
-        [DynamicDependency("Compile()", typeof(Expression<>))]
-        [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2070:UnrecognizedReflectionPattern",
-            Justification = "The 'Compile' method will be preserved by the DynamicDependency.")]
-        private static MethodInfo GetDerivedCompileMethod(Type lambdaExpressionType)
-        {
-            Debug.Assert(lambdaExpressionType.IsAssignableTo(typeof(LambdaExpression)) && lambdaExpressionType != typeof(LambdaExpression));
-
-            MethodInfo result = lambdaExpressionType.GetMethod("Compile", Type.EmptyTypes)!;
-            Debug.Assert(result.DeclaringType!.IsGenericType && result.DeclaringType.GetGenericTypeDefinition() == typeof(Expression<>));
-
-            return result;
+            return (MethodInfo)lambdaExpressionType.GetMemberWithSameMetadataDefinitionAs(s_expressionCompileMethodInfo);
         }
 
         /// <summary>
index c64c59a..99b0321 100644 (file)
   <data name="PlatformNotSupported_FileEncryption" xml:space="preserve">
     <value>File encryption is not supported on this platform.</value>
   </data>
+  <data name="Arg_MemberInfoNotFound" xml:space="preserve">
+    <value>A MemberInfo that matches '{0}' could not be found.</value>
+  </data>
 </root>
\ No newline at end of file
index f09c20a..d9de502 100644 (file)
@@ -126,6 +126,8 @@ namespace System.Reflection
         [DynamicallyAccessedMembers(GetAllMembers)]
         public override MemberInfo[] GetMembers(BindingFlags bindingAttr) => typeImpl.GetMembers(bindingAttr);
 
+        public override MemberInfo GetMemberWithSameMetadataDefinitionAs(MemberInfo member) => typeImpl.GetMemberWithSameMetadataDefinitionAs(member);
+
         protected override TypeAttributes GetAttributeFlagsImpl() => typeImpl.Attributes;
 
         public override bool IsTypeDefinition => typeImpl.IsTypeDefinition;
index ca57ed5..3c1a178 100644 (file)
@@ -226,6 +226,38 @@ namespace System
             DynamicallyAccessedMemberTypes.PublicNestedTypes)]
         public MemberInfo[] GetMembers() => GetMembers(Type.DefaultLookup);
 
+        /// <summary>
+        /// Searches for the <see cref="MemberInfo"/> on the current <see cref="Type"/> that matches the specified <see cref="MemberInfo"/>.
+        /// </summary>
+        /// <param name="member">
+        /// The <see cref="MemberInfo"/> to find on the current <see cref="Type"/>.
+        /// </param>
+        /// <returns>An object representing the member on the current <see cref="Type"/> that matches the specified member.</returns>
+        /// <remarks>This method can be used to find a constructed generic member given a member from a generic type definition.</remarks>
+        /// <exception cref="ArgumentNullException"><paramref name="member"/> is <see langword="null"/>.</exception>
+        /// <exception cref="ArgumentException"><paramref name="member"/> does not match a member on the current <see cref="Type"/>.</exception>
+        [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2085:UnrecognizedReflectionPattern",
+            Justification = "This is finding the MemberInfo with the same MetadataToken as specified MemberInfo. If the specified MemberInfo " +
+                            "exists and wasn't trimmed, then the current Type's MemberInfo couldn't have been trimmed.")]
+        public virtual MemberInfo GetMemberWithSameMetadataDefinitionAs(MemberInfo member)
+        {
+            if (member is null) throw new ArgumentNullException(nameof(member));
+
+            const BindingFlags all = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance;
+            foreach (MemberInfo myMemberInfo in GetMembers(all))
+            {
+                if (myMemberInfo.HasSameMetadataDefinitionAs(member))
+                {
+                    return myMemberInfo;
+                }
+            }
+
+            throw CreateGetMemberWithSameMetadataDefinitionAsNotFoundException(member);
+        }
+
+        private protected static ArgumentException CreateGetMemberWithSameMetadataDefinitionAsNotFoundException(MemberInfo member) =>
+            new ArgumentException(SR.Format(SR.Arg_MemberInfoNotFound, member.Name), nameof(member));
+
         [DynamicallyAccessedMembers(GetAllMembers)]
         public abstract MemberInfo[] GetMembers(BindingFlags bindingAttr);
 
index 4e3603c..f3b9240 100644 (file)
@@ -5,6 +5,8 @@ using System.Collections;
 using System.Collections.Generic;
 using System.IO;
 using System.Linq;
+using System.Reflection.Emit;
+using System.Runtime.CompilerServices;
 using System.Runtime.InteropServices;
 using Xunit;
 
@@ -1565,6 +1567,70 @@ namespace System.Reflection.Tests
             Assert.Equal(expected, type.GetTypeInfo().IsSZArray);
         }
 
+        public static IEnumerable<object[]> GetMemberWithSameMetadataDefinitionAsData()
+        {
+            yield return new object[] { typeof(TI_GenericTypeWithAllMembers<>), typeof(TI_GenericTypeWithAllMembers<int>), true };
+            yield return new object[] { typeof(TI_GenericTypeWithAllMembers<>), typeof(TI_GenericTypeWithAllMembers<ClassWithMultipleConstructors>), true};
+
+            yield return new object[] { typeof(TI_GenericTypeWithAllMembers<>), typeof(TI_TypeDerivedFromGenericTypeWithAllMembers<int>), false };
+            yield return new object[] { typeof(TI_GenericTypeWithAllMembers<>), typeof(TI_TypeDerivedFromGenericTypeWithAllMembers<ClassWithMultipleConstructors>), false };
+
+            yield return new object[] { typeof(TI_GenericTypeWithAllMembers<>), typeof(TI_TypeDerivedFromGenericTypeWithAllMembersClosed), false };
+
+            static TypeInfo GetTypeDelegator(Type t) => new TypeDelegator(t);
+            yield return new object[] { GetTypeDelegator(typeof(TI_GenericTypeWithAllMembers<>)), typeof(TI_GenericTypeWithAllMembers<ClassWithMultipleConstructors>), true };
+            yield return new object[] { typeof(TI_GenericTypeWithAllMembers<>), GetTypeDelegator(typeof(TI_GenericTypeWithAllMembers<ClassWithMultipleConstructors>)), true };
+            yield return new object[] { GetTypeDelegator(typeof(TI_GenericTypeWithAllMembers<>)), GetTypeDelegator(typeof(TI_GenericTypeWithAllMembers<ClassWithMultipleConstructors>)), true };
+
+            if (RuntimeFeature.IsDynamicCodeSupported)
+            {
+                (Type generatedType1, Type generatedType2) = CreateGeneratedTypes();
+
+                yield return new object[] { generatedType1, generatedType2, true };
+                yield return new object[] { generatedType2, generatedType1, true };
+            }
+        }
+
+        private static (Type, Type) CreateGeneratedTypes()
+        {
+            AssemblyBuilder assembly = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("GetMemberWithSameMetadataDefinitionAsGeneratedAssembly"), AssemblyBuilderAccess.Run);
+            ModuleBuilder module = assembly.DefineDynamicModule("GetMemberWithSameMetadataDefinitionAsGeneratedModule");
+            TypeBuilder genericType = module.DefineType("GenericGeneratedType");
+            genericType.DefineGenericParameters("T0");
+            genericType.DefineField("_int", typeof(int), FieldAttributes.Private);
+            genericType.DefineProperty("Prop", PropertyAttributes.None, typeof(string), null);
+
+            Type builtGenericType = genericType.CreateType();
+            Type closedType = builtGenericType.MakeGenericType(typeof(int));
+
+            return (genericType, closedType);
+        }
+
+        [Theory, MemberData(nameof(GetMemberWithSameMetadataDefinitionAsData))]
+        public void GetMemberWithSameMetadataDefinitionAs(Type openGenericType, Type closedGenericType, bool checkDeclaringType)
+        {
+            BindingFlags all = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly;
+            foreach (MemberInfo openGenericMember in openGenericType.GetMembers(all))
+            {
+                MemberInfo closedGenericMember = closedGenericType.GetMemberWithSameMetadataDefinitionAs(openGenericMember);
+                Assert.True(closedGenericMember != null, $"'{openGenericMember.Name}' was not found");
+                Assert.True(closedGenericMember.HasSameMetadataDefinitionAs(openGenericMember));
+                Assert.Equal(closedGenericMember.Name, openGenericMember.Name);
+                if (checkDeclaringType && openGenericMember is not Type)
+                {
+                    Assert.True(closedGenericMember.DeclaringType.Equals(closedGenericType), $"'{closedGenericMember.Name}' doesn't have the right DeclaringType");
+                }
+            }
+
+            MemberInfo toString = closedGenericType.GetMemberWithSameMetadataDefinitionAs(typeof(object).GetMethod("ToString"));
+            Assert.NotNull(toString);
+            Assert.IsAssignableFrom<MethodInfo>(toString);
+            Assert.Equal("ToString", toString.Name);
+
+            Assert.Throws<ArgumentNullException>(() => openGenericType.GetMemberWithSameMetadataDefinitionAs(null));
+            Assert.Throws<ArgumentException>(() => openGenericType.GetMemberWithSameMetadataDefinitionAs(typeof(string).GetMethod("get_Length")));
+        }
+
 #pragma warning disable 0067, 0169
         public static class ClassWithStaticConstructor
         {
@@ -1815,6 +1881,54 @@ namespace System.Reflection.Tests
         public abstract class AbstractSubClass : AbstractBaseClass { }
         public class AbstractSubSubClass : AbstractSubClass { }
     }
+
+    public class TI_GenericTypeWithAllMembers<T>
+    {
+        private static event EventHandler<T> PrivateStaticEvent;
+        private static T PrivateStaticField;
+        private static T PrivateStaticProperty { get; set; }
+        private static T PrivateStaticMethod(T t) => default;
+        private static T PrivateStaticMethod(T t, T t2) => default;
+
+        public static event EventHandler<T> PublicStaticEvent;
+        public static T PublicStaticField;
+        public static T PublicStaticProperty { get; set; }
+        public static T PublicStaticMethod(T t) => default;
+        public static T PublicStaticMethod(T t, T t2) => default;
+
+        static TI_GenericTypeWithAllMembers() { }
+
+        public TI_GenericTypeWithAllMembers(T t) { }
+        private TI_GenericTypeWithAllMembers() { }
+
+        public event EventHandler<T> PublicInstanceEvent;
+        public T PublicInstanceField;
+        public T PublicInstanceProperty { get; set; }
+        public T PublicInstanceMethod(T t) => default;
+        public T PublicInstanceMethod(T t, T t2) => default;
+
+        private event EventHandler<T> PrivateInstanceEvent;
+        private T PrivateInstanceField;
+        private T PrivateInstanceProperty { get; set; }
+        private T PrivateInstanceMethod(T t) => default;
+        private T PrivateInstanceMethod(T t1, T t2) => default;
+
+        public class Nested
+        {
+            public T NestedField;
+        }
+    }
+
+    public class TI_TypeDerivedFromGenericTypeWithAllMembers<T> : TI_GenericTypeWithAllMembers<T>
+    {
+        public TI_TypeDerivedFromGenericTypeWithAllMembers(T t) : base(t) { }
+    }
+
+    public class TI_TypeDerivedFromGenericTypeWithAllMembersClosed : TI_TypeDerivedFromGenericTypeWithAllMembers<int>
+    {
+        public TI_TypeDerivedFromGenericTypeWithAllMembersClosed(int t) : base(t) { }
+    }
+
 #pragma warning restore 0067, 0169
 
     public class OutsideTypeInfoTests
index d9eba92..9398d93 100644 (file)
@@ -16,6 +16,8 @@ namespace System.Runtime.Serialization
 
         private const string ObjectManagerUnreferencedCodeMessage = "ObjectManager is not trim compatible because the Type of objects being managed cannot be statically discovered.";
 
+        private static readonly FieldInfo s_nullableValueField = typeof(Nullable<>).GetField("value", BindingFlags.NonPublic | BindingFlags.Instance)!;
+
         private DeserializationEventHandler? _onDeserializationHandler;
         private SerializationEventHandler? _onDeserializedHandler;
 
@@ -383,14 +385,11 @@ namespace System.Runtime.Serialization
             return true;
         }
 
-        [DynamicDependency("value", typeof(Nullable<>))]
-        [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2070:UnrecognizedReflectionPattern",
-            Justification = "The Nullable<T>.value field will be preserved by the DynamicDependency.")]
         private static FieldInfo? GetNullableValueField(Type type)
         {
             if (Nullable.GetUnderlyingType(type) != null)
             {
-                return type.GetField("value", BindingFlags.NonPublic | BindingFlags.Instance)!;
+                return (FieldInfo)type.GetMemberWithSameMetadataDefinitionAs(s_nullableValueField);
             }
 
             return null;
index a251145..736ba37 100644 (file)
@@ -4485,6 +4485,7 @@ namespace System
         public virtual System.Reflection.MemberInfo[] GetMember(string name, System.Reflection.BindingFlags bindingAttr) { throw null; }
         [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.NonPublicConstructors | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.NonPublicEvents | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.NonPublicFields | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.NonPublicMethods | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.NonPublicNestedTypes | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.NonPublicProperties | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicEvents | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicFields | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicMethods | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicNestedTypes | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties)]
         public virtual System.Reflection.MemberInfo[] GetMember(string name, System.Reflection.MemberTypes type, System.Reflection.BindingFlags bindingAttr) { throw null; }
+        public virtual System.Reflection.MemberInfo GetMemberWithSameMetadataDefinitionAs(System.Reflection.MemberInfo member) { throw null; }
         [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicEvents | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicFields | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicMethods | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicNestedTypes | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties)]
         public System.Reflection.MemberInfo[] GetMembers() { throw null; }
         [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.NonPublicConstructors | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.NonPublicEvents | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.NonPublicFields | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.NonPublicMethods | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.NonPublicNestedTypes | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.NonPublicProperties | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicEvents | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicFields | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicMethods | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicNestedTypes | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties)]
index 2c7fbda..e92011c 100644 (file)
@@ -82,14 +82,6 @@ namespace System.Reflection
             return (RuntimeType)DeclaringType;
         }
 
-        private RuntimeType ReflectedTypeInternal
-        {
-            get
-            {
-                return (RuntimeType)ReflectedType;
-            }
-        }
-
         internal RuntimeModule GetRuntimeModule()
         {
             return GetDeclaringTypeInternal().GetRuntimeModule();
index b4a9c2f..15649ac 100644 (file)
@@ -63,14 +63,6 @@ namespace System.Reflection
             return (RuntimeType)DeclaringType!;
         }
 
-        private RuntimeType ReflectedTypeInternal
-        {
-            get
-            {
-                return (RuntimeType)ReflectedType;
-            }
-        }
-
         internal RuntimeModule GetRuntimeModule()
         {
             return GetDeclaringTypeInternal().GetRuntimeModule();
index aba9b94..362b999 100644 (file)
@@ -157,14 +157,6 @@ namespace System.Reflection
             }
         }
 
-        private RuntimeType? ReflectedTypeInternal
-        {
-            get
-            {
-                return (RuntimeType?)ReflectedType;
-            }
-        }
-
         private string FormatNameAndSig()
         {
             // Serialization uses ToString to resolve MethodInfo overloads.
@@ -788,14 +780,6 @@ namespace System.Reflection
             return RuntimeTypeHandle.GetModule((RuntimeType)DeclaringType);
         }
 
-        private RuntimeType? ReflectedTypeInternal
-        {
-            get
-            {
-                return (RuntimeType?)ReflectedType;
-            }
-        }
-
         public override MethodImplAttributes GetMethodImplementationFlags()
         {
             return MonoMethodInfo.GetMethodImplementationFlags(mhandle);
index 9e05a18..20defaa 100644 (file)
@@ -131,14 +131,6 @@ namespace System.Reflection
             return (RuntimeType)DeclaringType;
         }
 
-        private RuntimeType ReflectedTypeInternal
-        {
-            get
-            {
-                return (RuntimeType)ReflectedType;
-            }
-        }
-
         internal RuntimeModule GetRuntimeModule()
         {
             return GetDeclaringTypeInternal().GetRuntimeModule();
index 7b9c50c..241fee8 100644 (file)
@@ -7,7 +7,6 @@ using System.Threading;
 using System.Collections.Generic;
 using System.Runtime.Serialization;
 using System.Runtime.CompilerServices;
-using System.Diagnostics.Contracts;
 using System.Diagnostics.CodeAnalysis;
 using System.Runtime.InteropServices;
 using System.Diagnostics;
@@ -38,14 +37,6 @@ namespace System
                               FormatFullInst
     }
 
-    internal enum TypeNameKind
-    {
-        Name,
-        ToString,
-        SerializationName,
-        FullName,
-    }
-
     internal partial class RuntimeType
     {
         #region Definitions
@@ -1127,8 +1118,135 @@ namespace System
 
             return compressMembers;
         }
-        #endregion
 
+        public override MemberInfo GetMemberWithSameMetadataDefinitionAs(MemberInfo member)
+        {
+            if (member is null) throw new ArgumentNullException(nameof(member));
+
+            RuntimeType? runtimeType = this;
+            while (runtimeType != null)
+            {
+                MemberInfo? result = member.MemberType switch
+                {
+                    MemberTypes.Method => GetMethodWithSameMetadataDefinitionAs(runtimeType, member),
+                    MemberTypes.Constructor => GetConstructorWithSameMetadataDefinitionAs(runtimeType, member),
+                    MemberTypes.Property => GetPropertyWithSameMetadataDefinitionAs(runtimeType, member),
+                    MemberTypes.Field => GetFieldWithSameMetadataDefinitionAs(runtimeType, member),
+                    MemberTypes.Event => GetEventWithSameMetadataDefinitionAs(runtimeType, member),
+                    MemberTypes.NestedType => GetNestedTypeWithSameMetadataDefinitionAs(runtimeType, member),
+                    _ => null
+                };
+
+                if (result != null)
+                {
+                    return result;
+                }
+
+                runtimeType = runtimeType.GetBaseType();
+            }
+
+            throw CreateGetMemberWithSameMetadataDefinitionAsNotFoundException(member);
+        }
+
+        private const BindingFlags GetMemberWithSameMetadataDefinitionAsBindingFlags =
+            BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
+
+        private static MemberInfo? GetMethodWithSameMetadataDefinitionAs(RuntimeType runtimeType, MemberInfo methodInfo)
+        {
+            ListBuilder<MethodInfo> methods = runtimeType.GetMethodCandidates(methodInfo.Name, GetMemberWithSameMetadataDefinitionAsBindingFlags, CallingConventions.Any, null, -1, allowPrefixLookup: false);
+
+            for (int i = 0; i < methods.Count; i++)
+            {
+                MethodInfo candidate = methods[i];
+                if (candidate.HasSameMetadataDefinitionAs(methodInfo))
+                {
+                    return candidate;
+                }
+            }
+
+            return null;
+        }
+
+        private static MemberInfo? GetConstructorWithSameMetadataDefinitionAs(RuntimeType runtimeType, MemberInfo constructorInfo)
+        {
+            ListBuilder<ConstructorInfo> ctors = runtimeType.GetConstructorCandidates(null, GetMemberWithSameMetadataDefinitionAsBindingFlags, CallingConventions.Any, null, allowPrefixLookup: false);
+
+            for (int i = 0; i < ctors.Count; i++)
+            {
+                ConstructorInfo candidate = ctors[i];
+                if (candidate.HasSameMetadataDefinitionAs(constructorInfo))
+                {
+                    return candidate;
+                }
+            }
+
+            return null;
+        }
+
+        private static MemberInfo? GetPropertyWithSameMetadataDefinitionAs(RuntimeType runtimeType, MemberInfo propertyInfo)
+        {
+            ListBuilder<PropertyInfo> properties = runtimeType.GetPropertyCandidates(propertyInfo.Name, GetMemberWithSameMetadataDefinitionAsBindingFlags, null, allowPrefixLookup: false);
+
+            for (int i = 0; i < properties.Count; i++)
+            {
+                PropertyInfo candidate = properties[i];
+                if (candidate.HasSameMetadataDefinitionAs(propertyInfo))
+                {
+                    return candidate;
+                }
+            }
+
+            return null;
+        }
+
+        private static MemberInfo? GetFieldWithSameMetadataDefinitionAs(RuntimeType runtimeType, MemberInfo fieldInfo)
+        {
+            ListBuilder<FieldInfo> fields = runtimeType.GetFieldCandidates(fieldInfo.Name, GetMemberWithSameMetadataDefinitionAsBindingFlags, allowPrefixLookup: false);
+
+            for (int i = 0; i < fields.Count; i++)
+            {
+                FieldInfo candidate = fields[i];
+                if (candidate.HasSameMetadataDefinitionAs(fieldInfo))
+                {
+                    return candidate;
+                }
+            }
+
+            return null;
+        }
+
+        private static MemberInfo? GetEventWithSameMetadataDefinitionAs(RuntimeType runtimeType, MemberInfo eventInfo)
+        {
+            ListBuilder<EventInfo> events = runtimeType.GetEventCandidates(null, GetMemberWithSameMetadataDefinitionAsBindingFlags, allowPrefixLookup: false);
+
+            for (int i = 0; i < events.Count; i++)
+            {
+                EventInfo candidate = events[i];
+                if (candidate.HasSameMetadataDefinitionAs(eventInfo))
+                {
+                    return candidate;
+                }
+            }
+
+            return null;
+        }
+
+        private static MemberInfo? GetNestedTypeWithSameMetadataDefinitionAs(RuntimeType runtimeType, MemberInfo nestedType)
+        {
+            ListBuilder<Type> nestedTypes = runtimeType.GetNestedTypeCandidates(nestedType.Name, GetMemberWithSameMetadataDefinitionAsBindingFlags, allowPrefixLookup: false);
+
+            for (int i = 0; i < nestedTypes.Count; i++)
+            {
+                Type candidate = nestedTypes[i];
+                if (candidate.HasSameMetadataDefinitionAs(nestedType))
+                {
+                    return candidate;
+                }
+            }
+
+            return null;
+        }
+        #endregion
 
         #region Hierarchy