private static Type CheckWithDiscriminators(Type expectedType, IEnumerable <ITypeDiscriminator> supportedTypes, ParsingEventBuffer buffer) { foreach (var discriminator in supportedTypes) { buffer.Reset(); if (discriminator.TryResolve(buffer, out var actualType)) { CheckReturnedType(discriminator.BaseType, actualType); return(actualType); } } throw new Exception($"None of the registered type discriminators could supply a child class for {expectedType}"); }
public bool Deserialize(IParser reader, Type expectedType, Func <IParser, Type, object> nestedObjectDeserializer, out object value) { // we're essentially "in front of" the normal ObjectNodeDeserializer. // We could let it check if the current event is a mapping, but we also need to know. if (!reader.Accept <MappingStart>(out var mapping)) { value = null; return(false); } // can any of the registered discrimaintors deal with the abstract type? var supportedTypes = typeDiscriminators.Where(t => t.BaseType == expectedType); if (!supportedTypes.Any()) { // no? then not a node/type we want to deal with return(original.Deserialize(reader, expectedType, nestedObjectDeserializer, out value)); } // now buffer all the nodes in this mapping. // it'd be better if we did not have to do this, but YamlDotNet does not support non-streaming access. // See: https://github.com/aaubry/YamlDotNet/issues/343 // WARNING: This has the potential to be quite slow and add a lot of memory usage, especially for large documents. // It's better, if you use this at all, to use it on leaf mappings var start = reader.Current.Start; Type actualType; ParsingEventBuffer buffer; try { buffer = new ParsingEventBuffer(ReadNestedMapping(reader)); // use the discriminators to tell us what type it is really expecting by letting it inspect the parsing events actualType = CheckWithDiscriminators(expectedType, supportedTypes, buffer); } catch (Exception exception) { throw new YamlException(start, reader.Current.End, "Failed when resolving abstract type", exception); } // now continue by re-emitting parsing events buffer.Reset(); return(original.Deserialize(buffer, actualType, nestedObjectDeserializer, out value)); }