Esempio n. 1
0
        private static Func <DeserializationContext, object> ForComplex(Type type, TypeOptions options, Func <Type, TypeDescriptor> descriptorSource)
        {
            var info = type.GetTypeInfo();

            if (info.IsClass && info.GetConstructor(Type.EmptyTypes) == null)
            {
                return(reader => throw new JsonException(info.IsAbstract
                                        ? $"Type {type} is abstract. Add {nameof(ITypeSelector)} to {nameof(SerializationSettings)} in order to deserialize this type."
                                        : $"Type {type} must define public parameterless constructor."));
            }

            var properties = info
                             .GetProperties(BindingFlags.Instance | BindingFlags.Public)
                             .Where(i => i.SetMethod != null && i.GetMethod != null)
                             .Select(i => new { Property = (MemberInfo)i, Setter = ReflectionUtils.BuildSetter(i), Descriptor = descriptorSource(i.PropertyType) });

            var fields = info
                         .GetFields(BindingFlags.Instance | BindingFlags.Public)
                         .Select(i => new { Property = (MemberInfo)i, Setter = ReflectionUtils.BuildFieldSetter(i), Descriptor = descriptorSource(i.FieldType) });

            var all = properties
                      .Concat(fields)
                      .SelectMany(i => JsonNames(i.Property).Select(j => new PropertyBinding {
                Name = j, Setter = i.Setter, Descriptor = i.Descriptor
            }))
                      .GroupBy(i => i.Name)
                      .ToDictionary(i => i.Key, i => i.First());

            var constructor = info.IsClass
                                ? ReflectionUtils.BuildConstructor(type)
                                : () => Activator.CreateInstance(typeof(Box <>).MakeGenericType(type));

            //struct types are internally wrapped into Box<T> type (see ReflectionUtils)
            var unwrapper = !info.IsClass
                                ? new Func <object, object>(i => ((IBox)i).Value)
                                : null;

            return(context =>
            {
                var bufferPart = new BufferPart();
                var reader = context.Reader;
                var token = reader.Read(ref bufferPart, out var _);
                if (token == JsonToken.Null)
                {
                    return info.IsClass ? (object)null : throw new JsonException($"Unable to assign null value to struct type near line {reader.Line}, column {reader.Column}.");
                }
                if (token != JsonToken.ObjectStart)
                {
                    throw Exceptions.BadToken(reader, token, JsonToken.ObjectStart);
                }
                var target = constructor();
                var deferred = ReadProperties(target, context, all);
                var unwrapped = unwrapper != null?unwrapper(target) : target;

                if (deferred == null)
                {
                    return unwrapped;
                }

                foreach (var entry in deferred)
                {
                    var runtimeType = entry.Selector.FindPropertyType(entry.Binding.Name, unwrapped);
                    var descriptor = context.Catalog.GetDescriptor(runtimeType, options);
                    using (reader.LoadSnapshot(entry.Snapshot))
                        entry.Binding.Setter(target, descriptor.Reader(context));
                }
                return unwrapper != null?unwrapper(target) : target;
            });
        }