using System.Collections.ObjectModel; using System.Reflection; namespace Siggingway; internal static class NullabilityUtil { internal static bool IsNullable(PropertyInfo property) => IsNullableHelper(property.PropertyType, property.DeclaringType, property.CustomAttributes); internal static bool IsNullable(FieldInfo field) => IsNullableHelper(field.FieldType, field.DeclaringType, field.CustomAttributes); internal static bool IsNullable(ParameterInfo parameter) => IsNullableHelper(parameter.ParameterType, parameter.Member, parameter.CustomAttributes); private static bool IsNullableHelper(Type memberType, MemberInfo? declaringType, IEnumerable customAttributes) { if (memberType.IsValueType) { return Nullable.GetUnderlyingType(memberType) != null; } var nullable = customAttributes .FirstOrDefault(x => x.AttributeType.FullName == "System.Runtime.CompilerServices.NullableAttribute"); if (nullable != null && nullable.ConstructorArguments.Count == 1) { var attributeArgument = nullable.ConstructorArguments[0]; if (attributeArgument.ArgumentType == typeof(byte[])) { var args = (ReadOnlyCollection) attributeArgument.Value!; if (args.Count > 0 && args[0].ArgumentType == typeof(byte)) { return (byte) args[0].Value! == 2; } } else if (attributeArgument.ArgumentType == typeof(byte)) { return (byte) attributeArgument.Value! == 2; } } for (var type = declaringType; type != null; type = type.DeclaringType) { var context = type.CustomAttributes .FirstOrDefault(x => x.AttributeType.FullName == "System.Runtime.CompilerServices.NullableContextAttribute"); if (context != null && context.ConstructorArguments.Count == 1 && context.ConstructorArguments[0].ArgumentType == typeof(byte)) { return (byte) context.ConstructorArguments[0].Value! == 2; } } // Couldn't find a suitable attribute return false; } }