private static void ValidateNullability(object obj, ContextualType type, HashSet <object>?checkedObjects, List <string>?errors, bool stopFirstFail) { if (DisableNullabilityValidation) { return; } if (stopFirstFail && errors is not null && errors.Any()) { return; } if (checkedObjects != null) { if (checkedObjects.Contains(obj)) { return; } else { checkedObjects.Add(obj); } } if (checkedObjects != null && obj is IDictionary dictionary) { foreach (var item in dictionary.Keys.Cast <object>() .Concat(dictionary.Values.Cast <object>())) { ValidateNullability(item, type.GenericArguments[1], checkedObjects, errors, stopFirstFail); } } else if (checkedObjects != null && obj is IEnumerable enumerable && !(obj is string)) { var itemType = type.ElementType ?? type.GenericArguments[0]; foreach (var item in enumerable.Cast <object>()) { if (item == null) { if (itemType.Nullability == Nullability.NotNullable) { throw new InvalidOperationException( "The object's nullability is invalid, item in enumerable."); } } else { ValidateNullability(item, itemType, checkedObjects, errors, stopFirstFail); } } }
/// <summary> /// Gets a <see cref="CachedType"/> for the given <see cref="Type"/> instance. /// </summary> /// <param name="type">The type.</param> /// <returns>The <see cref="CachedType"/>.</returns> public static ContextualType ToContextualType(this Type type) { var key = "Type:Context:" + type.FullName; lock (Lock) { if (!Cache.ContainsKey(key)) { Cache[key] = ContextualType.ForType(type, new Attribute[0]); } return((ContextualType)Cache[key]); } }
internal ContextualType(Type type, IEnumerable <Attribute> contextAttributes, ContextualType parent, byte[] nullableFlags, ref int nullableFlagsIndex, IEnumerable <dynamic> customAttributeProviders) : base(type) { Parent = parent; ContextAttributes = contextAttributes is Attribute[]? (Attribute[])contextAttributes : contextAttributes?.ToArray() ?? new Attribute[0]; _nullableFlags = nullableFlags; InitializeNullableFlagsAndOriginalNullability(ref nullableFlagsIndex, customAttributeProviders); if (_nullableFlags != null) { UpdateOriginalGenericArguments(ref nullableFlagsIndex); } }
/// <summary> /// Gets an uncached <see cref="ContextualType"/> for the given <see cref="Type"/> instance and attributes. /// </summary> /// <param name="type">The type.</param> /// <param name="attributes">The attributes.</param> /// <returns>The <see cref="CachedType"/>.</returns> public static ContextualType ToContextualType(this Type type, IEnumerable <Attribute> attributes) { // TODO: Is there a way to cache these contextual types? return(ContextualType.ForType(type, attributes)); }