diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonPropertyInfo.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonPropertyInfo.cs index 2dfe2178b7ba51..375677a9d12b91 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonPropertyInfo.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonPropertyInfo.cs @@ -53,12 +53,8 @@ public JsonConverter? CustomConverter /// public Func? Get { - get => UntypedGetValue; - set - { - CheckMutable(); - UntypedGetValue = value; - } + get => _untypedGet; + set => SetGetter(value); } /// @@ -66,16 +62,15 @@ public JsonConverter? CustomConverter /// public Action? Set { - get => UntypedSetValue; - set - { - CheckMutable(); - UntypedSetValue = value; - } + get => _untypedSet; + set => SetSetter(value); } - private protected abstract Func? UntypedGetValue { get; set; } - private protected abstract Action? UntypedSetValue { get; set; } + private protected Func? _untypedGet; + private protected Action? _untypedSet; + + private protected abstract void SetGetter(Delegate? getter); + private protected abstract void SetSetter(Delegate? setter); /// /// Decides if property with given declaring object and property value should be serialized. @@ -136,7 +131,7 @@ internal static JsonPropertyInfo CreateIgnoredPropertyPlaceholder( /// public Type PropertyType { get; private protected set; } = null!; - private void CheckMutable() + private protected void CheckMutable() { if (_isConfigured) { @@ -443,8 +438,8 @@ internal string GetDebugInfo(int indent = 0) } #endif - internal bool HasGetter { get; set; } - internal bool HasSetter { get; set; } + internal bool HasGetter => _untypedGet is not null; + internal bool HasSetter => _untypedSet is not null; internal abstract void Initialize( Type parentClassType, diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonPropertyInfoOfT.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonPropertyInfoOfT.cs index 3ff813e1056209..b9a97e3bcbf6d4 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonPropertyInfoOfT.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonPropertyInfoOfT.cs @@ -27,45 +27,66 @@ internal sealed class JsonPropertyInfo : JsonPropertyInfo // the property's type, we track that and whether the property type can be null. private bool _propertyTypeEqualsTypeToConvert; - private Func? _untypedGet; - private Action? _untypedSet; + private Func? _typedGet; + private Action? _typedSet; - // We do not need to worry about invalidating _untypedGet/_untypedSet - // because these are only set during construction - // If these ever became public we'd need to ensure respective value is set to null here - private Func? TypedGetValue { get; set; } + internal new Func? Get + { + get => _typedGet; + set => SetGetter(value); + } - private Action? TypedSetValue { get; set; } + internal new Action? Set + { + get => _typedSet; + set => SetSetter(value); + } - private protected override Func? UntypedGetValue + private protected override void SetGetter(Delegate? getter) { - get + Debug.Assert(getter is null or Func or Func); + + CheckMutable(); + + if (getter is null) { - // We use local here so that we don't capture 'this' - Func? typedGetValue = TypedGetValue; - return _untypedGet ??= typedGetValue == null ? null : (o) => typedGetValue(o); + _typedGet = null; + _untypedGet = null; } - set + else if (getter is Func typedGetter) + { + _typedGet = typedGetter; + _untypedGet = getter is Func untypedGet ? untypedGet : obj => typedGetter(obj); + } + else { - _untypedGet = value; - TypedGetValue = value == null ? null : (o) => (T)value(o)!; - HasGetter = value != null; + Func untypedGet = (Func)getter; + _typedGet = (obj => (T)untypedGet(obj)!); + _untypedGet = untypedGet; } } - private protected override Action? UntypedSetValue + private protected override void SetSetter(Delegate? setter) { - get + Debug.Assert(setter is null or Action or Action); + + CheckMutable(); + + if (setter is null) { - // We use local here so that we don't capture 'this' - Action? typedSetValue = TypedSetValue; - return _untypedSet ??= typedSetValue == null ? null : (o, v) => typedSetValue(o, (T)v!); + _typedSet = null; + _untypedSet = null; } - set + else if (setter is Action typedSetter) + { + _typedSet = typedSetter; + _untypedSet = setter is Action untypedSet ? untypedSet : (obj, value) => typedSetter(obj, (T)value!); + } + else { - _untypedSet = value; - TypedSetValue = value == null ? null : (o, v) => value(o, v); - HasSetter = value != null; + Action untypedSet = (Action)setter; + _typedSet = ((obj, value) => untypedSet(obj, (T)value!)); + _untypedSet = untypedSet; } } @@ -112,15 +133,13 @@ internal override void Initialize( MethodInfo? getMethod = propertyInfo.GetMethod; if (getMethod != null && (getMethod.IsPublic || useNonPublicAccessors)) { - HasGetter = true; - TypedGetValue = options.MemberAccessorStrategy.CreatePropertyGetter(propertyInfo); + Get = options.MemberAccessorStrategy.CreatePropertyGetter(propertyInfo); } MethodInfo? setMethod = propertyInfo.SetMethod; if (setMethod != null && (setMethod.IsPublic || useNonPublicAccessors)) { - HasSetter = true; - TypedSetValue = options.MemberAccessorStrategy.CreatePropertySetter(propertyInfo); + Set = options.MemberAccessorStrategy.CreatePropertySetter(propertyInfo); } MemberType = MemberTypes.Property; @@ -132,13 +151,11 @@ internal override void Initialize( { Debug.Assert(fieldInfo.IsPublic); - HasGetter = true; - TypedGetValue = options.MemberAccessorStrategy.CreateFieldGetter(fieldInfo); + Get = options.MemberAccessorStrategy.CreateFieldGetter(fieldInfo); if (!fieldInfo.IsInitOnly) { - HasSetter = true; - TypedSetValue = options.MemberAccessorStrategy.CreateFieldSetter(fieldInfo); + Set = options.MemberAccessorStrategy.CreateFieldSetter(fieldInfo); } MemberType = MemberTypes.Field; @@ -158,8 +175,6 @@ internal override void Initialize( else if (!isCustomProperty) { IsForTypeInfo = true; - HasGetter = true; - HasSetter = true; } } @@ -213,10 +228,8 @@ internal void InitializeForSourceGen(JsonSerializerOptions options, JsonProperty } else { - TypedGetValue = propertyInfo.Getter!; - TypedSetValue = propertyInfo.Setter; - HasGetter = TypedGetValue != null; - HasSetter = TypedSetValue != null; + Get = propertyInfo.Getter!; + Set = propertyInfo.Setter; JsonTypeInfo = propertyTypeInfo; DeclaringType = declaringType; IgnoreCondition = propertyInfo.IgnoreCondition; @@ -277,12 +290,12 @@ internal override JsonConverter EffectiveConverter } Debug.Assert(HasGetter); - return TypedGetValue!(obj); + return Get!(obj); } internal override bool GetMemberAndWriteJson(object obj, ref WriteStack state, Utf8JsonWriter writer) { - T value = TypedGetValue!(obj); + T value = Get!(obj); if (ShouldSerialize != null) { @@ -384,7 +397,7 @@ value is not null && internal override bool GetMemberAndWriteJsonExtensionData(object obj, ref WriteStack state, Utf8JsonWriter writer) { bool success; - T value = TypedGetValue!(obj); + T value = Get!(obj); if (ShouldSerialize != null) { @@ -425,7 +438,7 @@ internal override bool ReadJsonAndSetMember(object obj, ref ReadStack state, ref if (!IgnoreDefaultValuesOnRead) { T? value = default; - TypedSetValue!(obj, value!); + Set!(obj, value!); } success = true; @@ -439,7 +452,7 @@ internal override bool ReadJsonAndSetMember(object obj, ref ReadStack state, ref { // Optimize for internal converters by avoiding the extra call to TryRead. T? fastValue = TypedEffectiveConverter.Read(ref reader, PropertyType, Options); - TypedSetValue!(obj, fastValue!); + Set!(obj, fastValue!); } success = true; @@ -470,7 +483,7 @@ internal override bool ReadJsonAndSetMember(object obj, ref ReadStack state, ref } } - TypedSetValue!(obj, value!); + Set!(obj, value!); } } } @@ -517,7 +530,7 @@ internal override void SetExtensionDictionaryAsObject(object obj, object? extens { Debug.Assert(HasSetter); T typedValue = (T)extensionDict!; - TypedSetValue!(obj, typedValue); + Set!(obj, typedValue); } } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonTypeInfoOfT.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonTypeInfoOfT.cs index ab23e9ac6ed13e..1d0af2d935f884 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonTypeInfoOfT.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonTypeInfoOfT.cs @@ -44,17 +44,8 @@ private protected override void SetCreateObject(Delegate? createObject, bool use } else if (createObject is Func typedDelegate) { - if (createObject is Func untypedDelegate) - { - untypedCreateObject = untypedDelegate; - } - else - { - // we will get here if T is value type - untypedCreateObject = () => typedDelegate()!; - } - typedCreateObject = typedDelegate; + untypedCreateObject = createObject is Func untypedDelegate ? untypedDelegate : () => typedDelegate()!; } else {