From: Steve Harter Date: Wed, 23 Sep 2020 14:52:41 +0000 (-0500) Subject: Make nullable-related checks consistent and faster (#42401) X-Git-Tag: submit/tizen/20210909.063632~5374 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=98fc7edd7fbfba0e0120dbd4533b1ad7c73cbb7d;p=platform%2Fupstream%2Fdotnet%2Fruntime.git Make nullable-related checks consistent and faster (#42401) --- diff --git a/src/libraries/System.Text.Json/src/System.Text.Json.csproj b/src/libraries/System.Text.Json/src/System.Text.Json.csproj index 7542db8..f1ddddb 100644 --- a/src/libraries/System.Text.Json/src/System.Text.Json.csproj +++ b/src/libraries/System.Text.Json/src/System.Text.Json.csproj @@ -1,4 +1,4 @@ - + true $(NetCoreAppCurrent);netstandard2.0;netcoreapp3.0;net461 @@ -182,7 +182,6 @@ - @@ -217,6 +216,7 @@ + diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/NullableConverterFactory.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/NullableConverterFactory.cs index 1967933..dfab566 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/NullableConverterFactory.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/NullableConverterFactory.cs @@ -10,7 +10,7 @@ namespace System.Text.Json.Serialization.Converters { public override bool CanConvert(Type typeToConvert) { - return Nullable.GetUnderlyingType(typeToConvert) != null; + return typeToConvert.IsNullableOfT(); } public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/GenericMethodHolder.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/GenericMethodHolder.cs index ef8e362..d321ab2 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/GenericMethodHolder.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/GenericMethodHolder.cs @@ -26,7 +26,7 @@ namespace System.Text.Json.Serialization { // For performance, we only want to call this method for non-nullable value types. // Nullable types should be checked againt 'null' before calling this method. - Debug.Assert(Nullable.GetUnderlyingType(value.GetType()) == null); + Debug.Assert(!value.GetType().CanBeNull()); return EqualityComparer.Default.Equals(default, (T)value); } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverterOfT.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverterOfT.cs index 38bd9cb..348c558 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverterOfT.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverterOfT.cs @@ -21,7 +21,7 @@ namespace System.Text.Json.Serialization // In the future, this will be check for !IsSealed (and excluding value types). CanBePolymorphic = TypeToConvert == JsonClassInfo.ObjectType; IsValueType = TypeToConvert.IsValueType; - CanBeNull = !IsValueType || Nullable.GetUnderlyingType(TypeToConvert) != null; + CanBeNull = !IsValueType || TypeToConvert.IsNullableOfT(); IsInternalConverter = GetType().Assembly == typeof(JsonConverter).Assembly; if (HandleNull) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfo.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfo.cs index f132019..4d7d9f4 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfo.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfo.cs @@ -12,7 +12,6 @@ namespace System.Text.Json internal abstract class JsonPropertyInfo { public static readonly JsonPropertyInfo s_missingProperty = GetPropertyPlaceholder(); - public static readonly Type s_NullableType = typeof(Nullable<>); private JsonClassInfo? _runtimeClassInfo; diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfoOfT.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfoOfT.cs index 612db8c..114858d 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfoOfT.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfoOfT.cs @@ -105,8 +105,7 @@ namespace System.Text.Json } _converterIsExternalAndPolymorphic = !converter.IsInternalConverter && DeclaredPropertyType != converter.TypeToConvert; - _propertyTypeCanBeNull = !DeclaredPropertyType.IsValueType || - (DeclaredPropertyType.IsGenericType && DeclaredPropertyType.GetGenericTypeDefinition() == s_NullableType); + _propertyTypeCanBeNull = DeclaredPropertyType.CanBeNull(); _propertyTypeEqualsTypeToConvert = typeof(T) == DeclaredPropertyType; GetPolicies(ignoreCondition, parentTypeNumberHandling, defaultValueIsNull: _propertyTypeCanBeNull); @@ -285,7 +284,7 @@ namespace System.Text.Json ThrowHelper.ThrowInvalidCastException_DeserializeUnableToAssignValue(typeOfValue, DeclaredPropertyType); } } - else if (DeclaredPropertyType.IsValueType && !DeclaredPropertyType.IsNullableValueType()) + else if (!_propertyTypeCanBeNull) { ThrowHelper.ThrowInvalidOperationException_DeserializeUnableToAssignNull(DeclaredPropertyType); } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.Converters.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.Converters.cs index 8d0c4f1..87049b4 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.Converters.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.Converters.cs @@ -185,7 +185,7 @@ namespace System.Text.Json // We also throw to avoid passing an invalid argument to setters for nullable struct properties, // which would cause an InvalidProgramException when the generated IL is invoked. // This is not an issue of the converter is wrapped in NullableConverter. - if (runtimePropertyType.IsNullableType() && !converter.TypeToConvert.IsNullableType()) + if (runtimePropertyType.CanBeNull() && !converter.TypeToConvert.CanBeNull()) { ThrowHelper.ThrowInvalidOperationException_ConverterCanConvertNullableRedundant(runtimePropertyType, converter); } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/TypeExtensions.cs b/src/libraries/System.Text.Json/src/System/Text/Json/TypeExtensions.cs deleted file mode 100644 index 8abbf6d..0000000 --- a/src/libraries/System.Text.Json/src/System/Text/Json/TypeExtensions.cs +++ /dev/null @@ -1,42 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; - -namespace System.Text.Json -{ - internal static class TypeExtensions - { - /// - /// Returns when the given type is of type . - /// - public static bool IsNullableValueType(this Type type) - { - return Nullable.GetUnderlyingType(type) != null; - } - - /// - /// Returns when the given type is either a reference type or of type . - /// - public static bool IsNullableType(this Type type) - { - return !type.IsValueType || IsNullableValueType(type); - } - - /// - /// Returns when the given type is assignable from . - /// - /// - /// Other than also returns when is of type where : and is of type . - /// - public static bool IsAssignableFromInternal(this Type type, Type from) - { - if (IsNullableValueType(from) && type.IsInterface) - { - return type.IsAssignableFrom(from.GetGenericArguments()[0]); - } - - return type.IsAssignableFrom(from); - } - } -} diff --git a/src/libraries/System.Text.Json/src/System/TypeExtensions.cs b/src/libraries/System.Text.Json/src/System/TypeExtensions.cs new file mode 100644 index 0000000..1e83527 --- /dev/null +++ b/src/libraries/System.Text.Json/src/System/TypeExtensions.cs @@ -0,0 +1,42 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Runtime.CompilerServices; + +namespace System.Text.Json +{ + internal static class TypeExtensions + { + private static readonly Type s_nullableType = typeof(Nullable<>); + + /// + /// Returns when the given type is of type . + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool IsNullableOfT(this Type type) => + type.IsGenericType && type.GetGenericTypeDefinition() == s_nullableType; + + /// + /// Returns when the given type is either a reference type or of type . + /// + /// This calls which is slow. If knowledge already exists + /// that the type is a value type, call instead. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool CanBeNull(this Type type) => + !type.IsValueType || type.IsNullableOfT(); + + /// + /// Returns when the given type is assignable from including support + /// when is by using the {T} generic parameter for . + /// + public static bool IsAssignableFromInternal(this Type type, Type from) + { + if (IsNullableOfT(from) && type.IsInterface) + { + return type.IsAssignableFrom(from.GetGenericArguments()[0]); + } + + return type.IsAssignableFrom(from); + } + } +}