Esempio n. 1
0
        public static bool TryFindMappingEntry(this ParsingEventBuffer parser, Func <Scalar, bool> selector, out Scalar key, out ParsingEvent value)
        {
            parser.Consume <MappingStart>();
            do
            {
                // so we only want to check keys in this mapping, don't descend
                switch (parser.Current)
                {
                case Scalar scalar:
                    // we've found a scalar, check if it's value matches one
                    // of our  predicate
                    var keyMatched = selector(scalar);

                    // move head so we can read or skip value
                    parser.MoveNext();

                    // read the value of the mapping key
                    if (keyMatched)
                    {
                        // success
                        value = parser.Current;
                        key   = scalar;
                        return(true);
                    }

                    // skip the value
                    parser.SkipThisAndNestedEvents();

                    break;

                case MappingStart or SequenceStart:
                    parser.SkipThisAndNestedEvents();
                    break;

                default:
                    // do nothing, skip to next node
                    parser.MoveNext();
                    break;
                }
            } while (parser.Current is not null);

            key   = null;
            value = null;
            return(false);
        }
        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));
        }
        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}");
        }