/// <inheritdoc/> public virtual bool Deserialize(IParser reader, Type expectedType, Func <IParser, Type, object> nestedObjectDeserializer, out object value) { value = null; if (!reader.Accept(out MappingStart mapping)) { return(false); } if (expectedType.IsInterface || !expectedType.IsAbstract || !expectedType.TryGetCustomAttribute(out DiscriminatorAttribute discriminatorAttribute)) { return(this.Inner.Deserialize(reader, expectedType, nestedObjectDeserializer, out value)); } if (!this.Resolvers.TryGetValue(expectedType, out AbstractTypeResolver resolver)) { resolver = new AbstractTypeResolver(expectedType); this.Resolvers.Add(expectedType, resolver); } ParsingEventStream stream = ParsingEventStream.Create(reader); if (!resolver.TryResolve(stream, out Type concreteType)) { throw new NullReferenceException($"Failed to resolve the concrete type for the abstract type '{expectedType.Name}'"); } stream.Reset(); return(this.Inner.Deserialize(stream, concreteType, nestedObjectDeserializer, out value)); }
/// <summary> /// Attempts to find the specified mapping entry /// </summary> /// <param name="parser">The <see cref="ParsingEventStream"/> to search</param> /// <param name="selector">A predicate <see cref="Func{T, TResult}"/> used to search the <see cref="ParsingEventStream"/> for a specific <see cref="ParsingEvent"/></param> /// <param name="key">The key of the matching <see cref="Scalar"/></param> /// <param name="value">The matching <see cref="Scalar"/>'s <see cref="ParsingEvent"/> </param> /// <returns>A boolean indicating whether or not the specified mapping entry could be found</returns> public static bool TryFindMappingEntry(this ParsingEventStream parser, Func <Scalar, bool> selector, out Scalar key, out ParsingEvent value) { parser.Consume <MappingStart>(); do { switch (parser.Current) { case Scalar scalar: var keyMatched = selector(scalar); parser.MoveNext(); if (keyMatched) { value = parser.Current; key = scalar; return(true); } parser.SkipThisAndNestedEvents(); break; case MappingStart or SequenceStart: parser.SkipThisAndNestedEvents(); break; default: parser.MoveNext(); break; } }while (parser.Current is not null); key = null; value = null; return(false); }
/// <summary> /// Attempts to resolve the abstract type's implementation based on the specified <see cref="ParsingEventStream"/> /// </summary> /// <param name="stream">The <see cref="ParsingEventStream"/> to use to resolve the implementation type</param> /// <param name="implementationType">The resulting implementation type</param> /// <returns>A boolean indicating whether or not the implementation type could be resolved thanks to the specified <see cref="ParsingEventStream"/></returns> public bool TryResolve(ParsingEventStream stream, out Type implementationType) { implementationType = null; if (stream.TryFindMappingEntry(scalar => { return(string.Equals(scalar.Value, this.DiscriminatorProperty.Name, StringComparison.InvariantCultureIgnoreCase)); }, out Scalar key, out ParsingEvent value)) { if (value is Scalar valueScalar) { return(this.TypeMappings.TryGetValue(valueScalar.Value.ToLower(), out implementationType)); } } return(false); }