<PackageReference Include="System.Text.Json" Version="8.0.0-preview.1.23110.8" />

JsonPropertyInfo

public abstract class JsonPropertyInfo
Provides JSON serialization-related metadata about a property or field.
using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Runtime.CompilerServices; using System.Text.Json.Reflection; namespace System.Text.Json.Serialization.Metadata { [System.Runtime.CompilerServices.NullableContext(1)] [System.Runtime.CompilerServices.Nullable(0)] [DebuggerDisplay("{DebuggerDisplay,nq}")] public abstract class JsonPropertyInfo { internal static readonly JsonPropertyInfo s_missingProperty = GetPropertyPlaceholder(); private JsonTypeInfo _jsonTypeInfo; private protected JsonConverter _effectiveConverter; private JsonConverter _customConverter; private protected Func<object, object> _untypedGet; private protected Action<object, object> _untypedSet; private bool _isUserSpecifiedSetter; private protected Func<object, object, bool> _shouldSerialize; private bool _isUserSpecifiedShouldSerialize; private JsonIgnoreCondition? _ignoreCondition; private ICustomAttributeProvider _attributeProvider; private bool _isExtensionDataProperty; private bool _isRequired; private volatile bool _isConfigured; private string _name; private int _order; private JsonNumberHandling? _numberHandling; private int _index; [System.Runtime.CompilerServices.Nullable(2)] internal JsonTypeInfo ParentTypeInfo { get; set; } internal JsonConverter EffectiveConverter => _effectiveConverter; [System.Runtime.CompilerServices.Nullable(2)] public JsonConverter CustomConverter { [System.Runtime.CompilerServices.NullableContext(2)] get { return _customConverter; } [System.Runtime.CompilerServices.NullableContext(2)] set { VerifyMutable(); _customConverter = value; } } [System.Runtime.CompilerServices.Nullable(new byte[] { 2, 1, 2 })] public Func<object, object> Get { [return: System.Runtime.CompilerServices.Nullable(new byte[] { 2, 1, 2 })] get { return _untypedGet; } [param: System.Runtime.CompilerServices.Nullable(new byte[] { 2, 1, 2 })] set { VerifyMutable(); SetGetter(value); } } [System.Runtime.CompilerServices.Nullable(new byte[] { 2, 1, 2 })] public Action<object, object> Set { [return: System.Runtime.CompilerServices.Nullable(new byte[] { 2, 1, 2 })] get { return _untypedSet; } [param: System.Runtime.CompilerServices.Nullable(new byte[] { 2, 1, 2 })] set { VerifyMutable(); SetSetter(value); _isUserSpecifiedSetter = true; } } [System.Runtime.CompilerServices.Nullable(new byte[] { 2, 1, 2 })] public Func<object, object, bool> ShouldSerialize { [return: System.Runtime.CompilerServices.Nullable(new byte[] { 2, 1, 2 })] get { return _shouldSerialize; } [param: System.Runtime.CompilerServices.Nullable(new byte[] { 2, 1, 2 })] set { VerifyMutable(); SetShouldSerialize(value); _isUserSpecifiedShouldSerialize = true; IgnoreDefaultValuesOnWrite = false; } } internal JsonIgnoreCondition? IgnoreCondition { get { return _ignoreCondition; } set { ConfigureIgnoreCondition(value); _ignoreCondition = value; } } [System.Runtime.CompilerServices.Nullable(2)] public ICustomAttributeProvider AttributeProvider { [System.Runtime.CompilerServices.NullableContext(2)] get { return _attributeProvider; } [System.Runtime.CompilerServices.NullableContext(2)] set { VerifyMutable(); _attributeProvider = value; } } [System.Runtime.CompilerServices.Nullable(2)] internal string MemberName { get; set; } internal MemberTypes MemberType { get; set; } internal bool IsVirtual { get; set; } public bool IsExtensionData { get { return _isExtensionDataProperty; } set { VerifyMutable(); if (value && !JsonTypeInfo.IsValidExtensionDataProperty(PropertyType)) ThrowHelper.ThrowInvalidOperationException_SerializationDataExtensionPropertyInvalid(this); _isExtensionDataProperty = value; } } public bool IsRequired { get { return _isRequired; } set { VerifyMutable(); _isRequired = value; } } public Type PropertyType { get; } internal bool IsConfigured => _isConfigured; internal bool HasGetter => _untypedGet != null; internal bool HasSetter => _untypedSet != null; internal bool IgnoreNullTokensOnRead { get; set; } internal bool IgnoreDefaultValuesOnWrite { get; set; } internal bool IgnoreReadOnlyMember { get { switch (MemberType) { case MemberTypes.Property: return Options.IgnoreReadOnlyProperties; case MemberTypes.Field: return Options.IgnoreReadOnlyFields; default: return false; } } } internal bool IsForTypeInfo { get; set; } public string Name { get { return _name; } set { VerifyMutable(); if (value == null) ThrowHelper.ThrowArgumentNullException("value"); _name = value; } } internal byte[] NameAsUtf8Bytes { get; set; } internal byte[] EscapedNameSection { get; set; } public JsonSerializerOptions Options { get; } public int Order { get { return _order; } set { VerifyMutable(); _order = value; } } internal Type DeclaringType { get; } internal JsonTypeInfo JsonTypeInfo { get { _jsonTypeInfo.EnsureConfigured(); return _jsonTypeInfo; } [param: System.Diagnostics.CodeAnalysis.AllowNull] set { _jsonTypeInfo = value; } } internal bool IsIgnored { get { JsonIgnoreCondition? ignoreCondition = _ignoreCondition; JsonIgnoreCondition jsonIgnoreCondition = JsonIgnoreCondition.Always; return (ignoreCondition.GetValueOrDefault() == jsonIgnoreCondition) & ignoreCondition.HasValue; } } internal bool CanSerialize { get; set; } internal bool CanDeserialize { get; set; } internal bool SrcGen_HasJsonInclude { get; set; } internal bool SrcGen_IsPublic { get; set; } public JsonNumberHandling? NumberHandling { get { return _numberHandling; } set { VerifyMutable(); _numberHandling = value; } } internal JsonNumberHandling? EffectiveNumberHandling { get; set; } internal abstract bool PropertyTypeCanBeNull { get; } [System.Runtime.CompilerServices.Nullable(2)] internal abstract object DefaultValue { get; } internal int RequiredPropertyIndex { get { return _index; } set { _index = value; } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] private string DebuggerDisplay { get { return $"""{PropertyType}""{Name}""{DeclaringType}"; } } private protected abstract void SetGetter(Delegate getter); private protected abstract void SetSetter(Delegate setter); private protected abstract void SetShouldSerialize(Delegate predicate); private protected abstract void ConfigureIgnoreCondition(JsonIgnoreCondition? ignoreCondition); internal JsonPropertyInfo(Type declaringType, Type propertyType, JsonTypeInfo declaringTypeInfo, JsonSerializerOptions options) { DeclaringType = declaringType; PropertyType = propertyType; ParentTypeInfo = declaringTypeInfo; Options = options; } internal static JsonPropertyInfo GetPropertyPlaceholder() { JsonPropertyInfo jsonPropertyInfo = new JsonPropertyInfo<object>(typeof(object), null, null); jsonPropertyInfo.Name = string.Empty; return jsonPropertyInfo; } private protected void VerifyMutable() { if (ParentTypeInfo?.IsReadOnly ?? false) ThrowHelper.ThrowInvalidOperationException_PropertyInfoImmutable(); } internal void EnsureConfigured() { if (!_isConfigured) { Configure(); _isConfigured = true; } } internal void Configure() { if (!IsForTypeInfo) CacheNameAsUtf8BytesAndEscapedNameSection(); if (_jsonTypeInfo == null) _jsonTypeInfo = Options.GetTypeInfoInternal(PropertyType, false, false); DetermineEffectiveConverter(_jsonTypeInfo); if (IsForTypeInfo) DetermineNumberHandlingForTypeInfo(); else { DetermineNumberHandlingForProperty(); DetermineIgnoreCondition(); DetermineSerializationCapabilities(); } if (IsRequired) { if (!CanDeserialize) ThrowHelper.ThrowInvalidOperationException_JsonPropertyRequiredAndNotDeserializable(this); if (IsExtensionData) ThrowHelper.ThrowInvalidOperationException_JsonPropertyRequiredAndExtensionData(this); } } private protected abstract void DetermineEffectiveConverter(JsonTypeInfo jsonTypeInfo); private protected abstract void DetermineMemberAccessors(MemberInfo memberInfo); private void DeterminePoliciesFromMember(MemberInfo memberInfo) { Order = (memberInfo.GetCustomAttribute<JsonPropertyOrderAttribute>(false)?.Order ?? 0); NumberHandling = memberInfo.GetCustomAttribute<JsonNumberHandlingAttribute>(false)?.Handling; } private void DeterminePropertyNameFromMember(MemberInfo memberInfo) { JsonPropertyNameAttribute customAttribute = memberInfo.GetCustomAttribute<JsonPropertyNameAttribute>(false); string text = (customAttribute != null) ? customAttribute.Name : ((Options.PropertyNamingPolicy == null) ? memberInfo.Name : Options.PropertyNamingPolicy.ConvertName(memberInfo.Name)); if (text == null) ThrowHelper.ThrowInvalidOperationException_SerializerPropertyNameNull(this); Name = text; } private void CacheNameAsUtf8BytesAndEscapedNameSection() { NameAsUtf8Bytes = Encoding.UTF8.GetBytes(Name); EscapedNameSection = JsonHelpers.GetEscapedPropertyNameSection(NameAsUtf8Bytes, Options.Encoder); } private void DetermineIgnoreCondition() { if (!_ignoreCondition.HasValue) { if (Options.IgnoreNullValues) { if (PropertyTypeCanBeNull) { IgnoreNullTokensOnRead = (!_isUserSpecifiedSetter && !IsRequired); IgnoreDefaultValuesOnWrite = (ShouldSerialize == null); } } else if (Options.DefaultIgnoreCondition == JsonIgnoreCondition.WhenWritingNull) { if (PropertyTypeCanBeNull) IgnoreDefaultValuesOnWrite = (ShouldSerialize == null); } else if (Options.DefaultIgnoreCondition == JsonIgnoreCondition.WhenWritingDefault) { IgnoreDefaultValuesOnWrite = (ShouldSerialize == null); } } } private void DetermineSerializationCapabilities() { CanSerialize = HasGetter; CanDeserialize = HasSetter; if (MemberType != 0 && !_ignoreCondition.HasValue) { if ((EffectiveConverter.ConverterStrategy & (ConverterStrategy)24) != 0) { if (Get == null && Set != null && !_isUserSpecifiedSetter) CanDeserialize = false; } else if (Get != null && Set == null && IgnoreReadOnlyMember && !_isUserSpecifiedShouldSerialize) { CanSerialize = false; } } } private void DetermineNumberHandlingForTypeInfo() { JsonNumberHandling? numberHandling = ParentTypeInfo.NumberHandling; if (numberHandling.HasValue) { JsonNumberHandling? nullable = numberHandling; JsonNumberHandling jsonNumberHandling = JsonNumberHandling.Strict; if (!((nullable.GetValueOrDefault() == jsonNumberHandling) & nullable.HasValue) && !EffectiveConverter.IsInternalConverter) ThrowHelper.ThrowInvalidOperationException_NumberHandlingOnPropertyInvalid(this); } if (NumberHandingIsApplicable()) { EffectiveNumberHandling = numberHandling; if (!EffectiveNumberHandling.HasValue && Options.NumberHandling != 0) EffectiveNumberHandling = Options.NumberHandling; } } private void DetermineNumberHandlingForProperty() { if (NumberHandingIsApplicable()) { JsonNumberHandling? effectiveNumberHandling = NumberHandling ?? ParentTypeInfo.NumberHandling ?? _jsonTypeInfo.NumberHandling; if (!effectiveNumberHandling.HasValue && Options.NumberHandling != 0) effectiveNumberHandling = Options.NumberHandling; EffectiveNumberHandling = effectiveNumberHandling; } else if (NumberHandling.HasValue) { JsonNumberHandling? numberHandling = NumberHandling; JsonNumberHandling jsonNumberHandling = JsonNumberHandling.Strict; if (!((numberHandling.GetValueOrDefault() == jsonNumberHandling) & numberHandling.HasValue)) ThrowHelper.ThrowInvalidOperationException_NumberHandlingOnPropertyInvalid(this); } } private bool NumberHandingIsApplicable() { if (EffectiveConverter.IsInternalConverterForNumberType) return true; Type type = (EffectiveConverter.IsInternalConverter && ((ConverterStrategy)24 & EffectiveConverter.ConverterStrategy) != 0) ? EffectiveConverter.ElementType : PropertyType; type = (Nullable.GetUnderlyingType(type) ?? type); if (!(type == typeof(byte)) && !(type == typeof(decimal)) && !(type == typeof(double)) && !(type == typeof(short)) && !(type == typeof(int)) && !(type == typeof(long)) && !(type == typeof(sbyte)) && !(type == typeof(float)) && !(type == typeof(ushort)) && !(type == typeof(uint)) && !(type == typeof(ulong))) return type == JsonTypeInfo.ObjectType; return true; } private void DetermineIsRequired(MemberInfo memberInfo, bool shouldCheckForRequiredKeyword) { IsRequired = (memberInfo.GetCustomAttribute<JsonRequiredAttribute>(false) != null || (shouldCheckForRequiredKeyword && memberInfo.HasRequiredMemberAttribute())); } internal abstract bool GetMemberAndWriteJson(object obj, ref WriteStack state, Utf8JsonWriter writer); internal abstract bool GetMemberAndWriteJsonExtensionData(object obj, ref WriteStack state, Utf8JsonWriter writer); internal abstract object GetValueAsObject(object obj); internal void InitializeUsingMemberReflection(MemberInfo memberInfo, JsonConverter customConverter, JsonIgnoreCondition? ignoreCondition, bool shouldCheckForRequiredKeyword) { ICustomAttributeProvider customAttributeProvider2 = AttributeProvider = memberInfo; ICustomAttributeProvider customAttributeProvider3 = customAttributeProvider2; PropertyInfo propertyInfo = customAttributeProvider3 as PropertyInfo; if ((object)propertyInfo == null) { FieldInfo fieldInfo = customAttributeProvider3 as FieldInfo; if ((object)fieldInfo != null) { MemberName = fieldInfo.Name; MemberType = MemberTypes.Field; } } else { MemberName = propertyInfo.Name; IsVirtual = propertyInfo.IsVirtual(); MemberType = MemberTypes.Property; } CustomConverter = customConverter; DeterminePoliciesFromMember(memberInfo); DeterminePropertyNameFromMember(memberInfo); DetermineIsRequired(memberInfo, shouldCheckForRequiredKeyword); JsonIgnoreCondition? nullable = ignoreCondition; JsonIgnoreCondition jsonIgnoreCondition = JsonIgnoreCondition.Always; if (!((nullable.GetValueOrDefault() == jsonIgnoreCondition) & nullable.HasValue)) DetermineMemberAccessors(memberInfo); IgnoreCondition = ignoreCondition; IsExtensionData = (memberInfo.GetCustomAttribute<JsonExtensionDataAttribute>(false) != null); } internal bool ReadJsonAndAddExtensionProperty(object obj, [System.Runtime.CompilerServices.ScopedRef] ref ReadStack state, ref Utf8JsonReader reader) { object valueAsObject = GetValueAsObject(obj); IDictionary<string, object> dictionary = valueAsObject as IDictionary<string, object>; if (dictionary != null) { if (reader.TokenType == JsonTokenType.Null) dictionary[state.Current.JsonPropertyNameAsString] = null; else { JsonConverter<object> jsonConverter = <ReadJsonAndAddExtensionProperty>g__GetDictionaryValueConverter|122_0<object>(); object value = jsonConverter.Read(ref reader, JsonTypeInfo.ObjectType, Options); dictionary[state.Current.JsonPropertyNameAsString] = value; } } else { IDictionary<string, JsonElement> dictionary2 = valueAsObject as IDictionary<string, JsonElement>; if (dictionary2 != null) { JsonConverter<JsonElement> jsonConverter2 = <ReadJsonAndAddExtensionProperty>g__GetDictionaryValueConverter|122_0<JsonElement>(); JsonElement value2 = jsonConverter2.Read(ref reader, typeof(JsonElement), Options); dictionary2[state.Current.JsonPropertyNameAsString] = value2; } else EffectiveConverter.ReadElementAndSetProperty(valueAsObject, state.Current.JsonPropertyNameAsString, ref reader, Options, ref state); } return true; } internal abstract bool ReadJsonAndSetMember(object obj, [System.Runtime.CompilerServices.ScopedRef] ref ReadStack state, ref Utf8JsonReader reader); internal abstract bool ReadJsonAsObject([System.Runtime.CompilerServices.ScopedRef] ref ReadStack state, ref Utf8JsonReader reader, out object value); internal bool ReadJsonExtensionDataValue([System.Runtime.CompilerServices.ScopedRef] ref ReadStack state, ref Utf8JsonReader reader, out object value) { if (JsonTypeInfo.ElementType == JsonTypeInfo.ObjectType && reader.TokenType == JsonTokenType.Null) { value = null; return true; } JsonConverter<JsonElement> jsonConverter = (JsonConverter<JsonElement>)Options.GetConverterInternal(typeof(JsonElement)); if (!jsonConverter.TryRead(ref reader, typeof(JsonElement), Options, ref state, out JsonElement value2)) { value = null; return false; } value = value2; return true; } internal void EnsureChildOf(JsonTypeInfo parent) { if (ParentTypeInfo == null) ParentTypeInfo = parent; else if (ParentTypeInfo != parent) { ThrowHelper.ThrowInvalidOperationException_JsonPropertyInfoIsBoundToDifferentJsonTypeInfo(this); } } } }