From 761c2b3d194ed728c7f517f81e549eaec891710d Mon Sep 17 00:00:00 2001 From: CaCTuCaTu4ECKuu Date: Sun, 11 Oct 2026 02:05:01 +0200 Subject: [PATCH] refactor: remove obsolete StreamingContext from enum deserialization Pass DeserializationErrorHandler directly to TolerantStringEnumConverter through a contract resolver instead of using StreamingContext. Remove the global JsonConvert.DefaultSettings mutation and obsolete StreamingContext helper classes. Preserve guidance for reporting unknown VK API enum values. --- .../IStreamingContextTypeDictionary.cs | 27 --------- .../StreamingContextExtensions.cs | 55 ------------------- .../StreamingContextTypeDataDictionary.cs | 16 ------ .../TolerantStringEnumConverter.cs | 50 ++++++++++++++--- VkNet/VkApi.cs | 14 +---- 5 files changed, 43 insertions(+), 119 deletions(-) delete mode 100644 VkNet/Infrastructure/IStreamingContextTypeDictionary.cs delete mode 100644 VkNet/Infrastructure/StreamingContextExtensions.cs delete mode 100644 VkNet/Infrastructure/StreamingContextTypeDataDictionary.cs diff --git a/VkNet/Infrastructure/IStreamingContextTypeDictionary.cs b/VkNet/Infrastructure/IStreamingContextTypeDictionary.cs deleted file mode 100644 index c2cfa814..00000000 --- a/VkNet/Infrastructure/IStreamingContextTypeDictionary.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System; -using JetBrains.Annotations; - -namespace VkNet.Infrastructure; - -/// -/// Интерфейс словаря контекста -/// -public interface IStreamingContextTypeDataDictionary -{ - /// - /// Добавить данные - /// - /// Тип - /// Данные - public void AddData(Type type, [CanBeNull] object data); - - /// - /// Попытка получения данных - /// - /// Тип - /// Данные - /// - /// Успешность получения данных - /// - public bool TryGetData(Type type, [CanBeNull] out object data); -} \ No newline at end of file diff --git a/VkNet/Infrastructure/StreamingContextExtensions.cs b/VkNet/Infrastructure/StreamingContextExtensions.cs deleted file mode 100644 index c69e408f..00000000 --- a/VkNet/Infrastructure/StreamingContextExtensions.cs +++ /dev/null @@ -1,55 +0,0 @@ -using System; -using System.Runtime.Serialization; -using JetBrains.Annotations; - -namespace VkNet.Infrastructure; - -/// -/// Класс для кэширования данных в StreamingContext -/// -public static class StreamingContextExtensions -{ - /// - /// Добавить данные в контекст - /// - /// Контекст данных - /// Тип - /// Данные - /// - /// Контекст - /// - public static StreamingContext AddTypeData(this StreamingContext context, Type type, [CanBeNull] object data) - { - var dictionary = context.Context switch - { - null => new StreamingContextTypeDataDictionary(), - IStreamingContextTypeDataDictionary d => d, - var _ => throw new InvalidOperationException($"context.Context is already populated with {context.Context}") - }; - - dictionary.AddData(type, data); - - return new(context.State, dictionary); - } - - /// - /// Попытка получения данных из контекста - /// - /// Контекст - /// Тип - /// Данные - /// - /// Успешность получения данных - /// - public static bool TryGetTypeData(this StreamingContext context, Type type, [CanBeNull] out object data) - { - if (context.Context is IStreamingContextTypeDataDictionary dictionary) - { - return dictionary.TryGetData(type, out data); - } - - data = null; - - return false; - } -} \ No newline at end of file diff --git a/VkNet/Infrastructure/StreamingContextTypeDataDictionary.cs b/VkNet/Infrastructure/StreamingContextTypeDataDictionary.cs deleted file mode 100644 index 1a04d35b..00000000 --- a/VkNet/Infrastructure/StreamingContextTypeDataDictionary.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace VkNet.Infrastructure; - -/// -internal class StreamingContextTypeDataDictionary : IStreamingContextTypeDataDictionary -{ - private readonly Dictionary _dictionary = new(); - - /// - public void AddData(Type type, object data) => _dictionary.Add(type, data); - - /// - public bool TryGetData(Type type, out object data) => _dictionary.TryGetValue(type, out data); -} \ No newline at end of file diff --git a/VkNet/Utils/JsonConverter/TolerantStringEnumConverter.cs b/VkNet/Utils/JsonConverter/TolerantStringEnumConverter.cs index 91ad5b4d..401ce60c 100644 --- a/VkNet/Utils/JsonConverter/TolerantStringEnumConverter.cs +++ b/VkNet/Utils/JsonConverter/TolerantStringEnumConverter.cs @@ -2,16 +2,25 @@ using Newtonsoft.Json; using Newtonsoft.Json.Converters; using Newtonsoft.Json.Serialization; -using VkNet.Infrastructure; namespace VkNet.Utils.JsonConverter; /// public class TolerantStringEnumConverter : StringEnumConverter { + private readonly bool? _ignoreUnknownValues; + /// public TolerantStringEnumConverter() => NamingStrategy = new SnakeCaseNamingStrategy(); + /// + /// Создает конвертер с указанным поведением для неизвестных значений enum. + /// + /// + /// Следует ли заменить неизвестное значение nullable enum на . + /// + public TolerantStringEnumConverter(bool? ignoreUnknownValues) : this() => _ignoreUnknownValues = ignoreUnknownValues; + /// public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { @@ -19,15 +28,12 @@ public class TolerantStringEnumConverter : StringEnumConverter { return base.ReadJson(reader, objectType, existingValue, serializer); } - catch (System.Exception e) + catch (System.Exception) { - var parameter = serializer.Context.TryGetTypeData(typeof(TolerantStringEnumConverter), out var s) - ? (bool?) s - : null; - - if (IsNullableType(objectType) && parameter is true) + if (IsNullableType(objectType) && _ignoreUnknownValues is true) { - //_logger.LogError($"\nПОЖАЛУЙСТА ОТКРОЙТЕ ISSUE: {$"https://github.com/vknet/vk/issues/new?title=Add%20new%20value%20to%20{objectType.GenericTypeArguments.FirstOrDefault()}&body={reader.Value}"}\n" + e.Message); + // Неизвестное значение может означать, что VK API добавил новый элемент enum. + // Создайте Issue: https://github.com/vknet/vk/issues/new, чтобы добавить его в соответствующий enum библиотеки. return null; } @@ -36,4 +42,30 @@ public class TolerantStringEnumConverter : StringEnumConverter } private static bool IsNullableType(Type t) => t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>); -} \ No newline at end of file +} + +/// +/// Настраивает конвертеры enum, заданные через . +/// +internal sealed class TolerantStringEnumContractResolver(bool? ignoreUnknownValues) : DefaultContractResolver +{ + protected override JsonContract CreateContract(Type objectType) + { + var contract = base.CreateContract(objectType); + contract.Converter = ReplaceTolerantConverter(contract.Converter); + + return contract; + } + + protected override JsonProperty CreateProperty(System.Reflection.MemberInfo member, MemberSerialization memberSerialization) + { + var property = base.CreateProperty(member, memberSerialization); + property.Converter = ReplaceTolerantConverter(property.Converter); + + return property; + } + + private Newtonsoft.Json.JsonConverter ReplaceTolerantConverter(Newtonsoft.Json.JsonConverter converter) => converter is TolerantStringEnumConverter + ? new TolerantStringEnumConverter(ignoreUnknownValues) + : converter; +} diff --git a/VkNet/VkApi.cs b/VkNet/VkApi.cs index bbc8cab7..03c99a5c 100644 --- a/VkNet/VkApi.cs +++ b/VkNet/VkApi.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Linq; using System.Runtime.CompilerServices; -using System.Runtime.Serialization; using System.Text; using System.Threading; using System.Threading.Tasks; @@ -271,22 +270,13 @@ public class VkApi : IVkApi { var answer = CallBase(methodName, parameters, skipAuthorization); - var context = new StreamingContext(StreamingContextStates.All) - .AddTypeData(typeof(TolerantStringEnumConverter), DeserializationErrorHandler); - - JsonConvert.DefaultSettings = () => new() - { - Context = context - }; - var settings = new JsonSerializerSettings { Converters = [], - ContractResolver = new DefaultContractResolver + ContractResolver = new TolerantStringEnumContractResolver(DeserializationErrorHandler) { NamingStrategy = new SnakeCaseNamingStrategy() }, - Context = context, MaxDepth = null, ReferenceLoopHandling = ReferenceLoopHandling.Ignore }; @@ -1062,4 +1052,4 @@ public class VkApi : IVkApi } #endregion -} \ No newline at end of file +}