Beispiel #1
0
        private static bool TryCreateNewObject(Type outputType, IReadOnlyDictionary <string, object> values, out object newObject)
        {
            // Create a default instance if one such constructor exists
            var contract = new ObjectContract(outputType); // TODO: Change this to some sort of factory for caching

            if (contract.HasDefaultConstructor)
            {
                newObject = contract.DefaultConstructor.Invoke(null);
                return(true);
            }
            if (contract.ParameterizedConstructor != null)
            {
                var parameters        = contract.ParameterizedConstructor.GetParameters();
                var orderedProperties =
                    values.Where(v => parameters.Any(p => p.Name.Equals(v.Key, StringComparison.InvariantCultureIgnoreCase)))
                    .OrderBy(v =>
                             parameters.IndexOf(parameters.First(p => p.Name.Equals(v.Key, StringComparison.InvariantCultureIgnoreCase))))
                    .Select(kv => kv.Value);
                newObject = contract.ParameterizedConstructor.Invoke(orderedProperties.ToArray());
                return(true);
            }

            newObject = null;
            return(false);
        }
Beispiel #2
0
        public object CreateNewObject(BitStreamReader reader, ObjectContract objectContract, DsdlProperty containerMember, DsdlProperty containerProperty, out bool createdFromNonDefaultCreator)
        {
            object newObject = null;

            if (objectContract.DefaultCreator != null && !objectContract.DefaultCreatorNonPublic)
            {
                // use the default constructor if it is...
                // public
                // non-public and the user has change constructor handling settings
                // non-public and there is no other creator
                newObject = objectContract.DefaultCreator();
            }

            if (newObject == null)
            {
                if (!objectContract.IsInstantiable)
                {
                    throw new SerializationException("Could not create an instance of type {0}. Type is an interface or abstract class and cannot be instantiated.".FormatWith(CultureInfo.InvariantCulture, objectContract.UnderlyingType));
                }

                throw new SerializationException("Unable to find a constructor to use for type {0}. A class should either have a default constructor, one constructor with arguments or a constructor marked with the JsonConstructor attribute.".FormatWith(CultureInfo.InvariantCulture, objectContract.UnderlyingType));
            }

            createdFromNonDefaultCreator = false;
            return(newObject);
        }
Beispiel #3
0
        private bool ShouldSetPropertyValue(DsdlProperty property, ObjectContract contract, object value)
        {
            if (!property.Writable)
            {
                return(false);
            }

            return(true);
        }
Beispiel #4
0
        void SerializeObject(BitStreamWriter writer, object value, ObjectContract contract, DsdlType derivedDsdlType, bool tailArrayOptimization)
        {
            var dsdlScheme = GetScheme <CompositeDsdlTypeBase>(contract, derivedDsdlType);

            _serializeStack.Push(value);

            SerializeObjectCore(
                writer,
                name => ResolveObjectProperty(value, contract, name),
                contract,
                derivedDsdlType,
                tailArrayOptimization);

            _serializeStack.Pop();
        }
Beispiel #5
0
        ResolvedProperty?ResolveObjectProperty(object value, ObjectContract contract, string name)
        {
            var property = contract.Properties.GetProperty(name, StringComparison.Ordinal);

            if (property == null)
            {
                return(null);
            }

            if (!CalculatePropertyValues(value, contract, property, out var memberContract, out var memberValue))
            {
                return(null);
            }

            return(new ResolvedProperty
            {
                Member = property,
                MemberContact = memberContract,
                MemberValue = memberValue
            });
        }
Beispiel #6
0
        private object PopulateObject(
            object newObject,
            BitStreamReader
            reader,
            ObjectContract contract,
            DsdlProperty member,
            CompositeDsdlTypeBase scheme,
            bool tailArrayOptimization)
        {
            foreach (var(field, tao) in EnumerateSchemeFields(reader, scheme, tailArrayOptimization))
            {
                if (field.Type is VoidDsdlType t)
                {
                    ReadAlignment(reader, t);
                    continue;
                }

                // attempt exact case match first
                // then try match ignoring case
                DsdlProperty property = contract.Properties.GetClosestMatchProperty(field.Name);

                if (property == null)
                {
                    throw new SerializationException($"Could not find member '{field.Name}' on object of type '{contract.UnderlyingType.FullName}'");
                }

                if (property.PropertyContract == null)
                {
                    property.PropertyContract = GetContractSafe(property.PropertyType);
                }

                SetPropertyValue(property, contract, member, reader, newObject, field.Type, tao);
            }

            return(newObject);
        }
Beispiel #7
0
        /// <summary>
        /// Binds the specified input string to an output object of a certain type.
        /// The value <paramref name="context" /> must be provided for performance reasons, as to avoid parsing the HTML tree multiple times.
        /// </summary>
        /// <param name="input">The input string.  See <see cref="BindingBehavior" /> for examples on what types of information may be passed in.</param>
        /// <param name="context">The context of the currently being-bound input value.  Generally the HTML element corresponding to the input value.</param>
        /// <param name="outputType">The type of output object to generate, whether a POCO, primitive, or other.</param>
        /// <param name="attribute">The optional attribute decorating the property that is currently being handled.</param>
        /// <returns>
        /// The output type object created, and filled with the parsed version of the <paramref name="input" />.
        /// </returns>
        public object Handle(string input, CQ context, Type outputType, BaseHtmlAttribute attribute)
        {
            if (context == null && input == null)
            {
                throw new ArgumentNullException(nameof(input), new ArgumentNullException(nameof(context)));
            }
            if (outputType == null)
            {
                throw new ArgumentNullException(nameof(outputType));
            }

            if (context == null)
            {
                context = new CQ(input);
            }

            var contract      = new ObjectContract(outputType);
            var allProperties = outputType.GetProperties();

            var properties = allProperties.Where(p => p.CanWrite)
                             .Union(
                allProperties.Where(p =>
                                    contract.Parameters.Any(
                                        param => param.Name.Equals(p.Name, StringComparison.InvariantCultureIgnoreCase))));

            // Changing this from setting to creating a hash table of values
            var values = properties.ToDictionary(property => property.Name, property =>
            {
                var propertyAttribute =
                    property.GetCustomAttributes(typeof(BaseHtmlAttribute), true).FirstOrDefault() as BaseHtmlAttribute;
                if (propertyAttribute != null)
                {
                    var enumerableInterface =
                        property.PropertyType.IsGenericType && property.PropertyType.GetGenericTypeDefinition() == typeof(IEnumerable <>) ?
                        property.PropertyType :
                        property.PropertyType.GetInterfaces()
                        .FirstOrDefault(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEnumerable <>));
                    var isEnumerable = enumerableInterface != null && property.PropertyType != typeof(string);

                    // Find
                    var typeOfFinder    = isEnumerable ? typeof(IEnumerable <CQ>) : typeof(CQ);
                    var nodeForProperty = FinderFactory.Instance.GetFinder(typeOfFinder)
                                          .Find(context, propertyAttribute.Selector);

                    // Verify
                    if (nodeForProperty != null)
                    {
                        object value;
                        var nodes      = nodeForProperty as IEnumerable <CQ>;
                        var singleNode = nodeForProperty as CQ;

                        if (nodes != null && isEnumerable)
                        {
                            value = BinderFactory.Instance.GetEnumerableBinder().Handle(nodes, property.PropertyType, propertyAttribute);
                        }
                        else if (singleNode != null)
                        {
                            // Single case
                            value = ParseAndBind(propertyAttribute, property.PropertyType, singleNode);
                        }
                        else
                        {
                            throw new NapBindingException($"Unknown finder type found: {nodeForProperty.GetType().FullName}");
                        }

                        return(value);
                    }
                }

                // Return default type otherwise
                return(property.PropertyType.IsValueType ? Activator.CreateInstance(property.PropertyType) : null);
            });

            // Construct using a greedy constructor mechanis
            object toReturn;

            if (TryCreateNewObject(outputType, values, out toReturn))
            {
                foreach (var value in values)
                {
                    // TODO: Add contract.Properties to cache PropertyInfos
                    var pi =
                        outputType.GetProperties(BindingFlags.Instance | BindingFlags.Public)
                        .FirstOrDefault(p => p.Name.Equals(value.Key, StringComparison.InvariantCultureIgnoreCase));
                    if (pi?.CanWrite ?? false)
                    {
                        pi.SetValue(toReturn, value.Value);
                    }
                }
            }

            return(toReturn);
        }