ReflectionExtensions
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.ExceptionServices;
using System.Text.Json.Serialization;
namespace System.Text.Json.Reflection
{
internal static class ReflectionExtensions
{
private const string ImmutableArrayGenericTypeName = "System.Collections.Immutable.ImmutableArray`1";
private const string ImmutableListGenericTypeName = "System.Collections.Immutable.ImmutableList`1";
private const string ImmutableListGenericInterfaceTypeName = "System.Collections.Immutable.IImmutableList`1";
private const string ImmutableStackGenericTypeName = "System.Collections.Immutable.ImmutableStack`1";
private const string ImmutableStackGenericInterfaceTypeName = "System.Collections.Immutable.IImmutableStack`1";
private const string ImmutableQueueGenericTypeName = "System.Collections.Immutable.ImmutableQueue`1";
private const string ImmutableQueueGenericInterfaceTypeName = "System.Collections.Immutable.IImmutableQueue`1";
private const string ImmutableSortedSetGenericTypeName = "System.Collections.Immutable.ImmutableSortedSet`1";
private const string ImmutableHashSetGenericTypeName = "System.Collections.Immutable.ImmutableHashSet`1";
private const string ImmutableSetGenericInterfaceTypeName = "System.Collections.Immutable.IImmutableSet`1";
private const string ImmutableDictionaryGenericTypeName = "System.Collections.Immutable.ImmutableDictionary`2";
private const string ImmutableDictionaryGenericInterfaceTypeName = "System.Collections.Immutable.IImmutableDictionary`2";
private const string ImmutableSortedDictionaryGenericTypeName = "System.Collections.Immutable.ImmutableSortedDictionary`2";
private const string ImmutableArrayTypeName = "System.Collections.Immutable.ImmutableArray";
private const string ImmutableListTypeName = "System.Collections.Immutable.ImmutableList";
private const string ImmutableStackTypeName = "System.Collections.Immutable.ImmutableStack";
private const string ImmutableQueueTypeName = "System.Collections.Immutable.ImmutableQueue";
private const string ImmutableSortedSetTypeName = "System.Collections.Immutable.ImmutableSortedSet";
private const string ImmutableHashSetTypeName = "System.Collections.Immutable.ImmutableHashSet";
private const string ImmutableDictionaryTypeName = "System.Collections.Immutable.ImmutableDictionary";
private const string ImmutableSortedDictionaryTypeName = "System.Collections.Immutable.ImmutableSortedDictionary";
public const string CreateRangeMethodName = "CreateRange";
private static readonly Type s_nullableType = typeof(Nullable<>);
public static Type GetCompatibleGenericBaseClass(this Type type, Type baseType)
{
if ((object)baseType == null)
return null;
Type type2 = type;
while (type2 != (Type)null && type2 != typeof(object)) {
if (type2.IsGenericType && type2.GetGenericTypeDefinition() == baseType)
return type2;
type2 = type2.BaseType;
}
return null;
}
[System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessage("ReflectionAnalysis", "IL2070:UnrecognizedReflectionPattern", Justification = "The 'interfaceType' must exist and so trimmer kept it. In which case It also kept it on any type which implements it. The below call to GetInterfaces may return fewer results when trimmed but it will return the 'interfaceType' if the type implemented it, even after trimming.")]
public static Type GetCompatibleGenericInterface(this Type type, Type interfaceType)
{
if ((object)interfaceType == null)
return null;
Type type2 = type;
if (type2.IsGenericType)
type2 = type2.GetGenericTypeDefinition();
if (type2 == interfaceType)
return type;
Type[] interfaces = type.GetInterfaces();
foreach (Type type3 in interfaces) {
if (type3.IsGenericType && type3.GetGenericTypeDefinition() == interfaceType)
return type3;
}
return null;
}
public static bool IsImmutableDictionaryType(this Type type)
{
if (type.IsGenericType && type.Assembly.FullName.StartsWith("System.Collections.Immutable", StringComparison.Ordinal)) {
switch (GetBaseNameFromGenericType(type)) {
case "System.Collections.Immutable.ImmutableDictionary`2":
case "System.Collections.Immutable.IImmutableDictionary`2":
case "System.Collections.Immutable.ImmutableSortedDictionary`2":
return true;
default:
return false;
}
}
return false;
}
public static bool IsImmutableEnumerableType(this Type type)
{
if (!type.IsGenericType || !type.Assembly.FullName.StartsWith("System.Collections.Immutable", StringComparison.Ordinal))
return false;
string baseNameFromGenericType = GetBaseNameFromGenericType(type);
if (baseNameFromGenericType != null) {
switch (baseNameFromGenericType.Length) {
case 45:
switch (baseNameFromGenericType[38]) {
case 'A':
break;
case 'e':
goto IL_00cd;
case 'S':
goto IL_00dc;
case 'Q':
goto IL_00eb;
default:
goto IL_0154;
}
if (!(baseNameFromGenericType == "System.Collections.Immutable.ImmutableArray`1"))
break;
goto IL_0152;
case 44:
switch (baseNameFromGenericType[30]) {
case 'm':
break;
case 'I':
goto IL_0109;
default:
goto IL_0154;
}
if (!(baseNameFromGenericType == "System.Collections.Immutable.ImmutableList`1"))
break;
goto IL_0152;
case 46:
switch (baseNameFromGenericType[39]) {
case 'S':
break;
case 'Q':
goto IL_0127;
default:
goto IL_0154;
}
if (!(baseNameFromGenericType == "System.Collections.Immutable.IImmutableStack`1"))
break;
goto IL_0152;
case 49:
if (!(baseNameFromGenericType == "System.Collections.Immutable.ImmutableSortedSet`1"))
break;
goto IL_0152;
case 47:
{
if (!(baseNameFromGenericType == "System.Collections.Immutable.ImmutableHashSet`1"))
break;
goto IL_0152;
}
IL_0127:
if (!(baseNameFromGenericType == "System.Collections.Immutable.IImmutableQueue`1"))
break;
goto IL_0152;
IL_00cd:
if (!(baseNameFromGenericType == "System.Collections.Immutable.IImmutableList`1"))
break;
goto IL_0152;
IL_0109:
if (!(baseNameFromGenericType == "System.Collections.Immutable.IImmutableSet`1"))
break;
goto IL_0152;
IL_0152:
return true;
IL_00eb:
if (!(baseNameFromGenericType == "System.Collections.Immutable.ImmutableQueue`1"))
break;
goto IL_0152;
IL_00dc:
if (!(baseNameFromGenericType == "System.Collections.Immutable.ImmutableStack`1"))
break;
goto IL_0152;
}
}
goto IL_0154;
IL_0154:
return false;
}
public static string GetImmutableDictionaryConstructingTypeName(this Type type)
{
switch (GetBaseNameFromGenericType(type)) {
case "System.Collections.Immutable.ImmutableDictionary`2":
case "System.Collections.Immutable.IImmutableDictionary`2":
return "System.Collections.Immutable.ImmutableDictionary";
case "System.Collections.Immutable.ImmutableSortedDictionary`2":
return "System.Collections.Immutable.ImmutableSortedDictionary";
default:
return null;
}
}
public static string GetImmutableEnumerableConstructingTypeName(this Type type)
{
string baseNameFromGenericType = GetBaseNameFromGenericType(type);
if (baseNameFromGenericType != null) {
switch (baseNameFromGenericType.Length) {
case 45:
switch (baseNameFromGenericType[38]) {
case 'A':
if (baseNameFromGenericType == "System.Collections.Immutable.ImmutableArray`1")
return "System.Collections.Immutable.ImmutableArray";
goto IL_0165;
case 'e':
break;
case 'S':
goto IL_00c6;
case 'Q':
goto IL_00d8;
default:
goto IL_0165;
}
if (!(baseNameFromGenericType == "System.Collections.Immutable.IImmutableList`1"))
break;
goto IL_0147;
case 44:
switch (baseNameFromGenericType[30]) {
case 'm':
break;
case 'I':
goto IL_00f6;
default:
goto IL_0165;
}
if (!(baseNameFromGenericType == "System.Collections.Immutable.ImmutableList`1"))
break;
goto IL_0147;
case 46:
switch (baseNameFromGenericType[39]) {
case 'S':
break;
case 'Q':
goto IL_0114;
default:
goto IL_0165;
}
if (!(baseNameFromGenericType == "System.Collections.Immutable.IImmutableStack`1"))
break;
goto IL_014d;
case 49:
if (baseNameFromGenericType == "System.Collections.Immutable.ImmutableSortedSet`1")
return "System.Collections.Immutable.ImmutableSortedSet";
break;
case 47:
{
if (!(baseNameFromGenericType == "System.Collections.Immutable.ImmutableHashSet`1"))
break;
goto IL_015f;
}
IL_00c6:
if (!(baseNameFromGenericType == "System.Collections.Immutable.ImmutableStack`1"))
break;
goto IL_014d;
IL_0114:
if (!(baseNameFromGenericType == "System.Collections.Immutable.IImmutableQueue`1"))
break;
goto IL_0153;
IL_014d:
return "System.Collections.Immutable.ImmutableStack";
IL_00f6:
if (!(baseNameFromGenericType == "System.Collections.Immutable.IImmutableSet`1"))
break;
goto IL_015f;
IL_015f:
return "System.Collections.Immutable.ImmutableHashSet";
IL_0147:
return "System.Collections.Immutable.ImmutableList";
IL_00d8:
if (!(baseNameFromGenericType == "System.Collections.Immutable.ImmutableQueue`1"))
break;
goto IL_0153;
IL_0153:
return "System.Collections.Immutable.ImmutableQueue";
}
}
goto IL_0165;
IL_0165:
return null;
}
private static string GetBaseNameFromGenericType(Type genericType)
{
return genericType.GetGenericTypeDefinition().FullName;
}
public static bool IsVirtual(this PropertyInfo propertyInfo)
{
if (!(propertyInfo.GetMethod?.IsVirtual ?? false))
return propertyInfo.SetMethod?.IsVirtual ?? false;
return true;
}
public static bool IsKeyValuePair(this Type type)
{
if (type.IsGenericType)
return type.GetGenericTypeDefinition() == typeof(KeyValuePair<, >);
return false;
}
public static bool TryGetDeserializationConstructor([System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers((System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes)7)] this Type type, bool useDefaultCtorInAnnotatedStructs, out ConstructorInfo deserializationCtor)
{
ConstructorInfo constructorInfo = null;
ConstructorInfo constructorInfo2 = null;
ConstructorInfo constructorInfo3 = null;
ConstructorInfo[] constructors = type.GetConstructors(BindingFlags.Instance | BindingFlags.Public);
if (constructors.Length == 1)
constructorInfo3 = constructors[0];
ConstructorInfo[] array = constructors;
foreach (ConstructorInfo constructorInfo4 in array) {
if (HasJsonConstructorAttribute(constructorInfo4)) {
if (constructorInfo != (ConstructorInfo)null) {
deserializationCtor = null;
return false;
}
constructorInfo = constructorInfo4;
} else if (constructorInfo4.GetParameters().Length == 0) {
constructorInfo2 = constructorInfo4;
}
}
array = type.GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic);
foreach (ConstructorInfo constructorInfo5 in array) {
if (HasJsonConstructorAttribute(constructorInfo5)) {
if (constructorInfo != (ConstructorInfo)null) {
deserializationCtor = null;
return false;
}
constructorInfo = constructorInfo5;
}
}
if (useDefaultCtorInAnnotatedStructs && type.IsValueType && constructorInfo == (ConstructorInfo)null) {
deserializationCtor = null;
return true;
}
deserializationCtor = (constructorInfo ?? constructorInfo2 ?? constructorInfo3);
return true;
}
public static object GetDefaultValue(this ParameterInfo parameterInfo)
{
Type parameterType = parameterInfo.ParameterType;
object defaultValue = parameterInfo.DefaultValue;
if (defaultValue == null)
return null;
if (defaultValue == DBNull.Value && parameterType != typeof(DBNull))
return null;
if (parameterType.IsEnum)
return Enum.ToObject(parameterType, defaultValue);
Type underlyingType = Nullable.GetUnderlyingType(parameterType);
if ((object)underlyingType != null && underlyingType.IsEnum)
return Enum.ToObject(underlyingType, defaultValue);
return defaultValue;
}
[System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Should only be used by the reflection-based serializer.")]
public static Type[] GetSortedTypeHierarchy(this Type type)
{
if (!type.IsInterface) {
List<Type> list = new List<Type>();
Type type2 = type;
while (type2 != (Type)null) {
list.Add(type2);
type2 = type2.BaseType;
}
return list.ToArray();
}
return JsonHelpers.TraverseGraphWithTopologicalSort(type, (Type t) => t.GetInterfaces(), null);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsNullableOfT(this Type type)
{
if (type.IsGenericType)
return type.GetGenericTypeDefinition() == s_nullableType;
return false;
}
public static bool IsNullableType(this Type type)
{
if (type.IsValueType)
return type.IsNullableOfT();
return true;
}
public static bool IsAssignableFromInternal(this Type type, Type from)
{
if (from.IsNullableOfT() && type.IsInterface)
return type.IsAssignableFrom(from.GetGenericArguments()[0]);
return type.IsAssignableFrom(from);
}
public static bool IsInSubtypeRelationshipWith(this Type type, Type other)
{
if (!type.IsAssignableFromInternal(other))
return other.IsAssignableFromInternal(type);
return true;
}
private static bool HasJsonConstructorAttribute(ConstructorInfo constructorInfo)
{
return constructorInfo.GetCustomAttribute<JsonConstructorAttribute>() != null;
}
public static bool HasRequiredMemberAttribute(this MemberInfo memberInfo)
{
return memberInfo.HasCustomAttributeWithName("System.Runtime.CompilerServices.RequiredMemberAttribute", false);
}
public static bool HasSetsRequiredMembersAttribute(this MemberInfo memberInfo)
{
return memberInfo.HasCustomAttributeWithName("System.Diagnostics.CodeAnalysis.SetsRequiredMembersAttribute", false);
}
private static bool HasCustomAttributeWithName(this MemberInfo memberInfo, string fullName, bool inherit)
{
object[] customAttributes = memberInfo.GetCustomAttributes(inherit);
for (int i = 0; i < customAttributes.Length; i++) {
if (customAttributes[i].GetType().FullName == fullName)
return true;
}
return false;
}
public static TAttribute GetUniqueCustomAttribute<TAttribute>(this MemberInfo memberInfo, bool inherit) where TAttribute : Attribute
{
object[] customAttributes = memberInfo.GetCustomAttributes(typeof(TAttribute), inherit);
if (customAttributes.Length == 0)
return null;
if (customAttributes.Length == 1)
return (TAttribute)customAttributes[0];
ThrowHelper.ThrowInvalidOperationException_SerializationDuplicateAttribute(typeof(TAttribute), memberInfo);
return null;
}
public static object CreateInstanceNoWrapExceptions([System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers((System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes)7)] this Type type, Type[] parameterTypes, object[] parameters)
{
ConstructorInfo constructor = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, parameterTypes, null);
object result = null;
try {
result = constructor.Invoke(parameters);
return result;
} catch (TargetInvocationException ex) {
ExceptionDispatchInfo.Capture(ex.InnerException).Throw();
return result;
}
}
public static ParameterInfo GetGenericParameterDefinition(this ParameterInfo parameter)
{
MemberInfo member = parameter.Member;
if ((object)member == null)
goto IL_003a;
Type declaringType = member.DeclaringType;
if ((object)declaringType == null || !declaringType.IsConstructedGenericType) {
MethodInfo methodInfo = member as MethodInfo;
if ((object)methodInfo == null || !methodInfo.IsGenericMethod || methodInfo.IsGenericMethodDefinition)
goto IL_003a;
}
bool flag = true;
goto IL_003c;
IL_003c:
if (flag)
return ((MethodBase)parameter.Member.GetGenericMemberDefinition()).GetParameters()[parameter.Position];
return parameter;
IL_003a:
flag = false;
goto IL_003c;
}
[System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessage("Trimming", "IL2075:'this' argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to target method. The return value of the source method does not have matching annotations.", Justification = "Looking up the generic member definition of the provided member.")]
public static MemberInfo GetGenericMemberDefinition(this MemberInfo member)
{
Type type = member as Type;
if ((object)type != null) {
if (!type.IsConstructedGenericType)
return type;
return type.GetGenericTypeDefinition();
}
if (member.DeclaringType.IsConstructedGenericType) {
MemberInfo[] member2 = member.DeclaringType.GetGenericTypeDefinition().GetMember(member.Name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
foreach (MemberInfo memberInfo in member2) {
if (memberInfo.MetadataToken == member.MetadataToken)
return memberInfo;
}
throw new Exception();
}
MethodInfo methodInfo = member as MethodInfo;
if ((object)methodInfo != null && methodInfo.IsGenericMethod && !methodInfo.IsGenericMethodDefinition)
return methodInfo.GetGenericMethodDefinition();
return member;
}
}
}