From 61de4354d5ac681fabc53ce14a4654d676845d4c Mon Sep 17 00:00:00 2001 From: Ivan Murzak Date: Sun, 9 Nov 2025 00:21:05 -0800 Subject: [PATCH 1/6] Enhance enum parsing to handle null values and improve nullable context handling in MethodUtils --- ReflectorNet/src/Convertor/Json/EnumJsonConverter.cs | 2 +- ReflectorNet/src/Reflector/MethodWrapper.cs | 2 +- ReflectorNet/src/Utils/MethodUtils.cs | 11 +++++++---- ReflectorNet/src/Utils/TypeUtils.cs | 5 +++-- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/ReflectorNet/src/Convertor/Json/EnumJsonConverter.cs b/ReflectorNet/src/Convertor/Json/EnumJsonConverter.cs index a85c272..d9ee084 100644 --- a/ReflectorNet/src/Convertor/Json/EnumJsonConverter.cs +++ b/ReflectorNet/src/Convertor/Json/EnumJsonConverter.cs @@ -63,7 +63,7 @@ public override bool CanConvert(Type typeToConvert) if (!Enum.TryParse(underlyingType, stringValue, ignoreCase: true, out var enumValue)) throw new JsonException($"Unable to convert '{stringValue}' to enum {underlyingType.Name}. Valid values are: {string.Join(", ", Enum.GetNames(underlyingType))}"); - if (Enum.IsDefined(underlyingType, enumValue)) + if (enumValue != null && Enum.IsDefined(underlyingType, enumValue)) return enumValue; throw new JsonException($"Unable to convert '{stringValue}' to enum {underlyingType.Name}. Valid values are: {string.Join(", ", Enum.GetNames(underlyingType))}"); diff --git a/ReflectorNet/src/Reflector/MethodWrapper.cs b/ReflectorNet/src/Reflector/MethodWrapper.cs index e1400ef..a7d3850 100644 --- a/ReflectorNet/src/Reflector/MethodWrapper.cs +++ b/ReflectorNet/src/Reflector/MethodWrapper.cs @@ -416,7 +416,7 @@ public virtual bool VerifyParameters(IReadOnlyDictionary? named { if (Enum.TryParse(parameterType, stringValue, ignoreCase: true, out var result)) { - if (Enum.IsDefined(parameterType, result)) + if (result != null && Enum.IsDefined(parameterType, result)) { return result; } diff --git a/ReflectorNet/src/Utils/MethodUtils.cs b/ReflectorNet/src/Utils/MethodUtils.cs index acb74dc..2bfa5dc 100644 --- a/ReflectorNet/src/Utils/MethodUtils.cs +++ b/ReflectorNet/src/Utils/MethodUtils.cs @@ -16,12 +16,15 @@ namespace com.IvanMurzak.ReflectorNet.Utils /// public static class MethodUtils { -#if NET5_0_OR_GREATER // Cache the NullableContextAttribute type for performance // This is a compiler-generated internal attribute, so we must access it by name - private static readonly Type? NullableContextAttributeType = typeof(System.Runtime.CompilerServices.NullableContextAttribute); - // Type.GetType("System.Runtime.CompilerServices.NullableContextAttribute, System.Private.CoreLib"); +#if NET8_0_OR_GREATER + private static readonly Type? NullableContextAttributeType = Type.GetType("System.Runtime.CompilerServices.NullableContextAttribute, System.Private.CoreLib"); +#elif NET5_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER + private static readonly Type NullableContextAttributeType = typeof(System.Runtime.CompilerServices.NullableContextAttribute); +#endif +#if NET5_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER // NullableContext attribute values private const byte NullableContextOblivious = 0; // No annotation - treat as non-nullable private const byte NullableContextNotNull = 1; // Non-nullable @@ -77,7 +80,7 @@ public static bool IsReturnTypeNullable(MethodInfo methodInfo) ? returnType.GetGenericArguments()[0] : returnType; -#if NET5_0_OR_GREATER +#if NET5_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER // First, check if this is a method on a generic type - we need to inspect the generic definition // to correctly determine nullability for generic type parameters (T vs T?) MethodInfo? methodToInspect = null; diff --git a/ReflectorNet/src/Utils/TypeUtils.cs b/ReflectorNet/src/Utils/TypeUtils.cs index 7cd07e3..936f721 100644 --- a/ReflectorNet/src/Utils/TypeUtils.cs +++ b/ReflectorNet/src/Utils/TypeUtils.cs @@ -10,7 +10,6 @@ using System.ComponentModel; using System.Linq; using System.Reflection; -using System.Text.Json.Schema; using com.IvanMurzak.ReflectorNet.Model; namespace com.IvanMurzak.ReflectorNet.Utils @@ -132,7 +131,8 @@ public static bool IsDictionary(Type type) var propertyInfo = type.GetProperty(propertyName); return propertyInfo != null ? GetPropertyDescription(propertyInfo) : null; } - public static string? GetPropertyDescription(JsonSchemaExporterContext context) +#if NETSTANDARD2_1_OR_GREATER || NET8_0_OR_GREATER + public static string? GetPropertyDescription(System.Text.Json.Schema.JsonSchemaExporterContext context) { if (context.PropertyInfo == null || context.PropertyInfo.DeclaringType == null) return null; @@ -169,6 +169,7 @@ public static bool IsDictionary(Type type) return GetDescription(memberInfo); } +#endif private static string ToPascalCase(string camelCase) { From cfa6028b30ebaa9cb45d52703496a24a1ccb96d6 Mon Sep 17 00:00:00 2001 From: Ivan Murzak Date: Sun, 9 Nov 2025 00:24:40 -0800 Subject: [PATCH 2/6] Fix nullable context attribute type declaration for compatibility with .NET 8 and earlier versions --- ReflectorNet/src/Utils/MethodUtils.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ReflectorNet/src/Utils/MethodUtils.cs b/ReflectorNet/src/Utils/MethodUtils.cs index 2bfa5dc..64020c3 100644 --- a/ReflectorNet/src/Utils/MethodUtils.cs +++ b/ReflectorNet/src/Utils/MethodUtils.cs @@ -19,9 +19,9 @@ public static class MethodUtils // Cache the NullableContextAttribute type for performance // This is a compiler-generated internal attribute, so we must access it by name #if NET8_0_OR_GREATER - private static readonly Type? NullableContextAttributeType = Type.GetType("System.Runtime.CompilerServices.NullableContextAttribute, System.Private.CoreLib"); -#elif NET5_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER private static readonly Type NullableContextAttributeType = typeof(System.Runtime.CompilerServices.NullableContextAttribute); +#elif NET5_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER + private static readonly Type? NullableContextAttributeType = Type.GetType("System.Runtime.CompilerServices.NullableContextAttribute, System.Private.CoreLib"); #endif #if NET5_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER From 8b6d205b7392beb1fc96165206612fea6614de90 Mon Sep 17 00:00:00 2001 From: Ivan Murzak Date: Sun, 9 Nov 2025 00:34:00 -0800 Subject: [PATCH 3/6] Remove unnecessary preprocessor directive for NullableContext attribute values in MethodUtils --- ReflectorNet/src/Utils/MethodUtils.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/ReflectorNet/src/Utils/MethodUtils.cs b/ReflectorNet/src/Utils/MethodUtils.cs index 64020c3..9058bcb 100644 --- a/ReflectorNet/src/Utils/MethodUtils.cs +++ b/ReflectorNet/src/Utils/MethodUtils.cs @@ -24,12 +24,10 @@ public static class MethodUtils private static readonly Type? NullableContextAttributeType = Type.GetType("System.Runtime.CompilerServices.NullableContextAttribute, System.Private.CoreLib"); #endif -#if NET5_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER // NullableContext attribute values private const byte NullableContextOblivious = 0; // No annotation - treat as non-nullable private const byte NullableContextNotNull = 1; // Non-nullable private const byte NullableContextNullable = 2; // Nullable -#endif /// /// Determines whether the return type of a method is nullable. From db85a27484256e09a64b33668e614315cdd3396f Mon Sep 17 00:00:00 2001 From: Ivan Murzak Date: Sun, 9 Nov 2025 00:40:30 -0800 Subject: [PATCH 4/6] Clarify comment for NullableContextAttributeType definition in MethodUtils for better understanding of environment support --- ReflectorNet/src/Utils/MethodUtils.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ReflectorNet/src/Utils/MethodUtils.cs b/ReflectorNet/src/Utils/MethodUtils.cs index 9058bcb..f0455e6 100644 --- a/ReflectorNet/src/Utils/MethodUtils.cs +++ b/ReflectorNet/src/Utils/MethodUtils.cs @@ -20,7 +20,7 @@ public static class MethodUtils // This is a compiler-generated internal attribute, so we must access it by name #if NET8_0_OR_GREATER private static readonly Type NullableContextAttributeType = typeof(System.Runtime.CompilerServices.NullableContextAttribute); -#elif NET5_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER +#elif NET5_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER // Maybe some environment would support it private static readonly Type? NullableContextAttributeType = Type.GetType("System.Runtime.CompilerServices.NullableContextAttribute, System.Private.CoreLib"); #endif From 5d24f4c734cc19c58d80fdbed25a36d8f2945527 Mon Sep 17 00:00:00 2001 From: Ivan Murzak Date: Sun, 9 Nov 2025 00:45:21 -0800 Subject: [PATCH 5/6] Update ReflectorNet/src/Reflector/MethodWrapper.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- ReflectorNet/src/Reflector/MethodWrapper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ReflectorNet/src/Reflector/MethodWrapper.cs b/ReflectorNet/src/Reflector/MethodWrapper.cs index a7d3850..5ad7f8a 100644 --- a/ReflectorNet/src/Reflector/MethodWrapper.cs +++ b/ReflectorNet/src/Reflector/MethodWrapper.cs @@ -416,7 +416,7 @@ public virtual bool VerifyParameters(IReadOnlyDictionary? named { if (Enum.TryParse(parameterType, stringValue, ignoreCase: true, out var result)) { - if (result != null && Enum.IsDefined(parameterType, result)) + if (Enum.IsDefined(parameterType, result!)) { return result; } From 177cb3cb52ff84afe85392884030979116decd75 Mon Sep 17 00:00:00 2001 From: Ivan Murzak Date: Sun, 9 Nov 2025 00:45:37 -0800 Subject: [PATCH 6/6] Update ReflectorNet/src/Convertor/Json/EnumJsonConverter.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- ReflectorNet/src/Convertor/Json/EnumJsonConverter.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ReflectorNet/src/Convertor/Json/EnumJsonConverter.cs b/ReflectorNet/src/Convertor/Json/EnumJsonConverter.cs index d9ee084..c23daf2 100644 --- a/ReflectorNet/src/Convertor/Json/EnumJsonConverter.cs +++ b/ReflectorNet/src/Convertor/Json/EnumJsonConverter.cs @@ -63,8 +63,8 @@ public override bool CanConvert(Type typeToConvert) if (!Enum.TryParse(underlyingType, stringValue, ignoreCase: true, out var enumValue)) throw new JsonException($"Unable to convert '{stringValue}' to enum {underlyingType.Name}. Valid values are: {string.Join(", ", Enum.GetNames(underlyingType))}"); - if (enumValue != null && Enum.IsDefined(underlyingType, enumValue)) - return enumValue; + if (Enum.IsDefined(underlyingType, enumValue!)) + return enumValue!; throw new JsonException($"Unable to convert '{stringValue}' to enum {underlyingType.Name}. Valid values are: {string.Join(", ", Enum.GetNames(underlyingType))}"); }