public NullableTypeTree Create(Type t, NullabilityTypeKind kind, NullableTypeTree[] subTypes, Type[]?genericArguments = null) { if (genericArguments?.Length == 2) { var tGen = t.GetGenericTypeDefinition(); if (tGen == typeof(IDictionary <,>) || tGen == typeof(Dictionary <,>)) { var tKey = subTypes[0]; if (tKey.Kind.IsNullable() && tKey.Kind.IsReferenceType()) { subTypes[0] = tKey.ToAbnormalNull(); } } } return(new NullableTypeTree(t, kind, subTypes)); }
/// <summary> /// Initializes a new <see cref="NullableTypeTree"/>. /// No checks are done on the parameters (except ArgumentNullException and the fact that <paramref name="t"/> must not be Nullable<>): /// they must be coherent otherwise behavior is undefined. /// </summary> /// <param name="t">The Type.</param> /// <param name="k">The <see cref="NullabilityTypeKind"/>.</param> /// <param name="subTypes">The sub types (generic parameters or array element).</param> public NullableTypeTree(Type t, NullabilityTypeKind k, NullableTypeTree[] subTypes) { if (t == null) { throw new ArgumentNullException(nameof(t)); } if (subTypes == null) { throw new ArgumentNullException(nameof(subTypes)); } if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable <>)) { throw new ArgumentException("Cannot be a Nullable<>.", nameof(t)); } Type = t; Kind = k; _rawSubTypes = subTypes; }
public bool IsAssignableFrom(Type target, NullabilityTypeKind targetNullability, Type from, NullabilityTypeKind fromNullability) { if (from == null) { throw new ArgumentNullException(nameof(from)); } if (target == null) { throw new ArgumentNullException(nameof(target)); } // A non nullable cannot be assigned from a nullable. if (!targetNullability.IsNullable() && fromNullability.IsNullable()) { return(false); } return(target == from || target.IsAssignableFrom(from) || (AllInterfaces.TryGetValue(target, out var tP) && AllInterfaces.TryGetValue(from, out var fP) && tP.Root == fP.Root)); }
/// <summary> /// Gets a readable string. /// </summary> /// <param name="this">This info.</param> /// <returns>A readable string.</returns> public static string ToStringClear(this NullabilityTypeKind @this) { var s = (@this & ~(NullabilityTypeKind.NRTFullNonNullable | NullabilityTypeKind.NRTFullNullable)).ToString(); if (@this.IsNRTAware()) { s += " (NRT"; if (@this.IsNRTFullNonNullable()) { s += ":FullNonNull)"; } else if (@this.IsNRTFullNullable()) { s += ":FullNull)"; } else { s += ":Profile)"; } } return(s); }
public bool IsAssignableFrom(IPocoPropertyInfo target, Type from, NullabilityTypeKind fromNullability) { if (from == null) { throw new ArgumentNullException(nameof(from)); } if (target == null) { throw new ArgumentNullException(nameof(target)); } if (target.PropertyUnionTypes.Any()) { foreach (var t in target.PropertyUnionTypes) { if (IsAssignableFrom(t.Type, t.Kind, from, fromNullability)) { return(true); } } return(false); } return(IsAssignableFrom(target.PropertyType, target.PropertyNullableTypeTree.Kind, from, fromNullability)); }
bool IPocoSupportResult.IsAssignableFrom(Type target, NullabilityTypeKind targetNullability, Type from, NullabilityTypeKind fromNullability) => false;
bool IPocoSupportResult.IsAssignableFrom(IPocoPropertyInfo target, Type from, NullabilityTypeKind fromNullability) => false;
static NullableTypeTree GetNullableTypeTreeWithProfile(Type t, IEnumerator <byte> annotations, NullabilityTypeKind known, INullableTypeTreeBuilder?builder) { if (t.DeclaringType != null && t.DeclaringType.IsGenericType) { throw new ArgumentException($"Type '{t.Name}' is nested in a generic type ({t.DeclaringType.ToCSharpName()}). Only nested types in non generic types are supported.", nameof(t)); } NullableTypeTree[] sub = Array.Empty <NullableTypeTree>(); bool isInside; if (isInside = (known == NullabilityTypeKind.None)) { known = t.GetNullabilityKind(); } if (known.IsNullableValueType()) { // Lift the Nullable<T>. t = Nullable.GetUnderlyingType(t) !; } if (isInside && !known.IsNonGenericValueType()) { // Consume our annotation. if (!annotations.MoveNext()) { throw new InvalidOperationException($"Byte annotations too short."); } var thisOne = annotations.Current; // Annotations only apply to reference types. Only 1 (not null!) is of interest. if (thisOne == 1 && known.IsReferenceType()) { Debug.Assert(known.IsNullable()); known &= ~NullabilityTypeKind.IsNullable; } } Type[]? genArgs = null; if (t.HasElementType) { Debug.Assert(known.IsReferenceType()); sub = new[] { GetNullableTypeTreeWithProfile(t.GetElementType() !, annotations, default, builder) };
/// <summary> /// Gets whether this is a nullable value type. /// Byte annotation is skipped and the inner type must be lifted: <see cref="NullabilityTypeKind.IsGenericType"/> and <see cref="NullabilityTypeKind.IsTupleType"/> /// apply to the inner type. /// </summary> /// <param name="this">This <see cref="NullabilityTypeKind"/>.</param> /// <returns>True for nullable value type.</returns> public static bool IsNullableValueType(this NullabilityTypeKind @this) => (@this & (NullabilityTypeKind.IsNullable | NullabilityTypeKind.IsValueType)) == (NullabilityTypeKind.IsNullable | NullabilityTypeKind.IsValueType);
/// <summary> /// Gets whether this is a technically nullable type. /// Challenging null on a variable of this type should be done either because it is a nullable value type /// or a reference type (be it NRT nullable or not). /// </summary> /// <param name="this">This <see cref="NullabilityTypeKind"/>.</param> /// <returns>True for type that can be null (even if they shouldn't).</returns> public static bool IsTechnicallyNullable(this NullabilityTypeKind @this) => (@this & (NullabilityTypeKind.IsNullable | NullabilityTypeKind.IsReferenceType)) != 0;
/// <summary> /// Gets whether this is a value type. /// This simply check the <see cref="NullabilityTypeKind.IsValueType"/> bit. /// </summary> /// <param name="this">This <see cref="NullabilityTypeKind"/>.</param> /// <returns>True for value type.</returns> public static bool IsValueType(this NullabilityTypeKind @this) => (@this & NullabilityTypeKind.IsValueType) != 0;
/// <summary> /// Gets whether this is a NRT that is fully non nullable. /// See <see cref="NullabilityTypeKind.NRTFullNonNullable"/>. /// </summary> /// <param name="this">This <see cref="NullabilityTypeKind"/>.</param> /// <returns>True for Nullable Reference Type fully null.</returns> public static bool IsNRTFullNonNullable(this NullabilityTypeKind @this) => (@this & (NullabilityTypeKind.NRTFullNonNullable | NullabilityTypeKind.NRTFullNullable)) == NullabilityTypeKind.NRTFullNonNullable;
/// <summary> /// Gets whether this is a non generic value type. /// Byte annotation is skipped. /// </summary> /// <param name="this">This <see cref="NullabilityTypeKind"/>.</param> /// <returns>True for non generic value types.</returns> public static bool IsNonGenericValueType(this NullabilityTypeKind @this) => (@this & (NullabilityTypeKind.IsValueType | NullabilityTypeKind.IsGenericType)) == NullabilityTypeKind.IsValueType;
/// <summary> /// Gets whether this has the <see cref="NullabilityTypeKind.IsReferenceType"/> flag. /// </summary> /// <param name="this">This <see cref="NullabilityTypeKind"/>.</param> /// <returns>True for reference types.</returns> public static bool IsReferenceType(this NullabilityTypeKind @this) => (@this & NullabilityTypeKind.IsReferenceType) != 0;
/// <summary> /// Initializes a new <see cref="NullabilityTypeInfo"/>. /// </summary> /// <param name="kind">The <see cref="Kind"/>.</param> /// <param name="nullableProfile">The optional <see cref="NullableProfile"/>.</param> /// <param name="fromContext">See <see cref="FromContext"/>.</param> public NullabilityTypeInfo(NullabilityTypeKind kind, byte[]?nullableProfile, bool fromContext) { Kind = kind; _profile = nullableProfile; FromContext = fromContext; }