Exemple #1
0
        /// <summary>
        /// Gets a value which indicates if should be ignored in Json serialization.
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static bool IsXmlIgnore(object value)
        {
            if (value == null)
            {
                return(false);
            }

            Type type = value.GetType();

            ICustomAttributeProvider provider = null;

            if (TCU.GetTypeInfo(type).IsEnum)
            {
                provider = TCU.GetTypeInfo(type).GetField(Enum.GetName(type, value));
            }
            else
            {
                provider = value as ICustomAttributeProvider;
            }

            if (provider == null)
            {
                throw new ArgumentException();
            }

#if !UNITY3D
            return(provider.IsDefined(typeof(XmlIgnoreAttribute), true));
#else
            return(false);
#endif
        }
Exemple #2
0
 /** Returns a member map if suitable for the object type.
  * Dictionary types will make this method return null
  */
 public Dictionary <string, MemberInfo> GetMemberMap(Type objectType)
 {
     // don't incurr the cost of member map for dictionaries
     if (TCU.GetTypeInfo(typeof(IDictionary)).IsAssignableFrom(TCU.GetTypeInfo(objectType)))
     {
         return(null);
     }
     else
     {
         return(this.CreateMemberMap(objectType));
     }
 }
Exemple #3
0
        /// <summary>
        /// Gets the name specified for use in Json serialization.
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static string GetJsonName(object value)
        {
            if (value == null)
            {
                return(null);
            }

            Type       type       = value.GetType();
            MemberInfo memberInfo = null;

            if (TCU.GetTypeInfo(type).IsEnum)
            {
                string name = Enum.GetName(type, value);
                if (String.IsNullOrEmpty(name))
                {
                    return(null);
                }
                memberInfo = TCU.GetTypeInfo(type).GetField(name);
            }
            else
            {
                memberInfo = value as MemberInfo;
            }

            if (MemberInfo.Equals(memberInfo, null))
            {
                throw new ArgumentException();
            }

#if WINDOWS_STORE
            JsonNameAttribute attribute = memberInfo.GetCustomAttribute <JsonNameAttribute> (true);
#else
            JsonNameAttribute attribute = Attribute.GetCustomAttribute(memberInfo, typeof(JsonNameAttribute)) as JsonNameAttribute;
#endif
            return(attribute != null ? attribute.Name : null);
        }
Exemple #4
0
        protected virtual void Write(object value, bool isProperty, Type fieldType = null, bool skipConverters = false)
        {
            if (isProperty && this.settings.PrettyPrint)
            {
                this.Writer.Write(' ');
            }

            if (value == null)
            {
                this.Writer.Write(JsonReader.LiteralNull);
                return;
            }

            if (value is IJsonSerializable && !skipConverters)
            {
                try
                {
                    if (isProperty)
                    {
                        this.depth++;
                        if (this.depth > this.settings.MaxDepth)
                        {
                            throw new JsonSerializationException(String.Format(JsonWriter.ErrorMaxDepth, new System.Object[] { this.settings.MaxDepth }));
                        }
                        this.WriteLine();
                    }
                    ((IJsonSerializable)value).WriteJson(this);
                }
                finally
                {
                    if (isProperty)
                    {
                        this.depth--;
                    }
                }
                return;
            }

            // must test enumerations before value types
            if (value is Enum)
            {
                this.Write((Enum)value);
                return;
            }

            // Type.GetTypeCode() allows us to more efficiently switch type
            // plus cannot use 'is' for ValueTypes
            Type type = value.GetType();

#if WINDOWS_STORE
            if (Type.Equals(type, typeof(bool)))
            {
                this.Write((Boolean)value);
                return;
            }
            else if (Type.Equals(type, typeof(System.Int32)))
            {
                this.Write((Int32)value);
                return;
            }
            else if (Type.Equals(type, typeof(System.Single)))
            {
                this.Write((Single)value);
                return;
            }
            else if (Type.Equals(type, typeof(System.String)))
            {
                this.Write((String)value);
                return;
            }
            else if (Type.Equals(type, typeof(byte)))
            {
                this.Write((Byte)value);
                return;
            }
            else if (Type.Equals(type, typeof(char)))
            {
                this.Write((Char)value);
                return;
            }
            else if (Type.Equals(type, typeof(DateTime)))
            {
                this.Write((DateTime)value);
                return;
            }
            else if (Type.Equals(type, typeof(DBNull)) || Type.Equals(type, null))
            {
                this.Writer.Write(JsonReader.LiteralNull);
                return;
            }
            else if (Type.Equals(type, typeof(Decimal)))
            {
                // From MSDN:
                // Conversions from Char, SByte, Int16, Int32, Int64, Byte, UInt16, UInt32, and UInt64
                // to Decimal are widening conversions that never lose information or throw exceptions.
                // Conversions from Single or Double to Decimal throw an OverflowException
                // if the result of the conversion is not representable as a Decimal.
                this.Write((Decimal)value);
                return;
            }
            else if (Type.Equals(type, typeof(double)))
            {
                this.Write((Double)value);
                return;
            }
            else if (Type.Equals(type, typeof(System.Int16)))
            {
                this.Write((Int16)value);
                return;
            }
            else if (Type.Equals(type, typeof(System.Int64)))
            {
                this.Write((Int64)value);
                return;
            }
            else if (Type.Equals(type, typeof(System.SByte)))
            {
                this.Write((SByte)value);
                return;
            }
            else if (Type.Equals(type, typeof(System.UInt16)))
            {
                this.Write((UInt16)value);
                return;
            }
            else if (Type.Equals(type, typeof(System.UInt32)))
            {
                this.Write((UInt32)value);
                return;
            }
            else if (Type.Equals(type, typeof(System.UInt64)))
            {
                this.Write((UInt64)value);
                return;
            }
            else
            {
                // all others must be explicitly tested
            }
#else
            // Faster to switch on typecode, but Windows Store does not support it
            switch (TP.GetTypeCode(type))
            {
            case TypeCode.Boolean:
            {
                this.Write((Boolean)value);
                return;
            }

            case TypeCode.Byte:
            {
                this.Write((Byte)value);
                return;
            }

            case TypeCode.Char:
            {
                this.Write((Char)value);
                return;
            }

            case TypeCode.DateTime:
            {
                this.Write((DateTime)value);
                return;
            }

            case TypeCode.DBNull:
            case TypeCode.Empty:
            {
                this.Writer.Write(JsonReader.LiteralNull);
                return;
            }

            case TypeCode.Decimal:
            {
                // From MSDN:
                // Conversions from Char, SByte, Int16, Int32, Int64, Byte, UInt16, UInt32, and UInt64
                // to Decimal are widening conversions that never lose information or throw exceptions.
                // Conversions from Single or Double to Decimal throw an OverflowException
                // if the result of the conversion is not representable as a Decimal.
                this.Write((Decimal)value);
                return;
            }

            case TypeCode.Double:
            {
                this.Write((Double)value);
                return;
            }

            case TypeCode.Int16:
            {
                this.Write((Int16)value);
                return;
            }

            case TypeCode.Int32:
            {
                this.Write((Int32)value);
                return;
            }

            case TypeCode.Int64:
            {
                this.Write((Int64)value);
                return;
            }

            case TypeCode.SByte:
            {
                this.Write((SByte)value);
                return;
            }

            case TypeCode.Single:
            {
                this.Write((Single)value);
                return;
            }

            case TypeCode.String:
            {
                this.Write((String)value);
                return;
            }

            case TypeCode.UInt16:
            {
                this.Write((UInt16)value);
                return;
            }

            case TypeCode.UInt32:
            {
                this.Write((UInt32)value);
                return;
            }

            case TypeCode.UInt64:
            {
                this.Write((UInt64)value);
                return;
            }

            default:
            case TypeCode.Object:
            {
                // all others must be explicitly tested
                break;
            }
            }
#endif

            if (!skipConverters)
            {
                JsonConverter converter = this.Settings.GetConverter(type);
                if (converter != null)
                {
                    // Return if converter serialized the object
                    if (converter.Write(this, depth, type, value))
                    {
                        return;
                    }
                }
            }

            if (value is Guid)
            {
                this.Write((Guid)value);
                return;
            }

            if (value is Uri)
            {
                this.Write((Uri)value);
                return;
            }

            if (value is TimeSpan)
            {
                this.Write((TimeSpan)value);
                return;
            }

            if (value is Version)
            {
                this.Write((Version)value);
                return;
            }

            // IDictionary test must happen BEFORE IEnumerable test
            // since IDictionary implements IEnumerable
            if (value is IDictionary)
            {
                try
                {
                    if (isProperty)
                    {
                        this.depth++;
                        if (this.depth > this.settings.MaxDepth)
                        {
                            throw new JsonSerializationException(String.Format(JsonWriter.ErrorMaxDepth, new System.Object[] { this.settings.MaxDepth }));
                        }
                        this.WriteLine();
                    }
                    this.WriteObject((IDictionary)value);
                }
                finally
                {
                    if (isProperty)
                    {
                        this.depth--;
                    }
                }
                return;
            }

            //if (!Type.Equals (TCU.GetTypeInfo(type).GetInterface (JsonReader.TypeGenericIDictionary), null))
            if (TCU.GetTypeInfo(typeof(IDictionary)).IsAssignableFrom(TCU.GetTypeInfo(value.GetType())))
            {
                try {
                    if (isProperty)
                    {
                        this.depth++;
                        if (this.depth > this.settings.MaxDepth)
                        {
                            throw new JsonSerializationException(String.Format(JsonWriter.ErrorMaxDepth, new System.Object[] { this.settings.MaxDepth }));
                        }
                        this.WriteLine();
                    }

                    this.WriteDictionary((IEnumerable)value);
                } finally {
                    if (isProperty)
                    {
                        this.depth--;
                    }
                }
                return;
            }

            if (value is IList && type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List <>))
            {
                // Is List<T>
                var memberType = type.GetGenericArguments() [0];

                try
                {
                    if (isProperty)
                    {
                        this.depth++;
                        if (this.depth > this.settings.MaxDepth)
                        {
                            throw new JsonSerializationException(String.Format(JsonWriter.ErrorMaxDepth, new System.Object[] { this.settings.MaxDepth }));
                        }
                        this.WriteLine();
                    }

                    this.WriteArray((IEnumerable)value, memberType);
                }
                finally
                {
                    if (isProperty)
                    {
                        this.depth--;
                    }
                }
                return;
            }

            // IDictionary test must happen BEFORE IEnumerable test
            // since IDictionary implements IEnumerable
            if (value is IEnumerable)
            {
#if !UNITY3D
                if (value is XmlNode)
                {
                    this.Write((System.Xml.XmlNode)value);
                    return;
                }
#endif
                try
                {
                    if (isProperty)
                    {
                        this.depth++;
                        if (this.depth > this.settings.MaxDepth)
                        {
                            throw new JsonSerializationException(String.Format(JsonWriter.ErrorMaxDepth, new System.Object[] { this.settings.MaxDepth }));
                        }
                        this.WriteLine();
                    }

                    this.WriteArray((IEnumerable)value, type.GetElementType());
                }
                finally
                {
                    if (isProperty)
                    {
                        this.depth--;
                    }
                }
                return;
            }

            // structs and classes
            try
            {
                if (isProperty)
                {
                    this.depth++;
                    if (this.depth > this.settings.MaxDepth)
                    {
                        throw new JsonSerializationException(String.Format(JsonWriter.ErrorMaxDepth, new System.Object[] { this.settings.MaxDepth }));
                    }
                    this.WriteLine();
                }
                this.WriteObject(value, type, true, fieldType);
            }
            finally
            {
                if (isProperty)
                {
                    this.depth--;
                }
            }
        }
Exemple #5
0
        protected virtual void WriteObject(object value, Type type, bool serializePrivate, Type fieldType = null)
        {
            bool appendDelim = false;

            if (settings.HandleCyclicReferences && !TCU.GetTypeInfo(type).IsValueType)
            {
                int prevIndex = 0;
                if (this.previouslySerializedObjects.TryGetValue(value, out prevIndex))
                {
                    this.Writer.Write(JsonReader.OperatorObjectStart);
                    this.WriteObjectProperty("@ref", prevIndex);
                    this.WriteLine();
                    this.Writer.Write(JsonReader.OperatorObjectEnd);
                    return;
                }
                else
                {
                    this.previouslySerializedObjects.Add(value, this.previouslySerializedObjects.Count);
                }
            }

            this.Writer.Write(JsonReader.OperatorObjectStart);

            this.depth++;
            if (this.depth > this.settings.MaxDepth)
            {
                throw new JsonSerializationException(String.Format(JsonWriter.ErrorMaxDepth, new System.Object[] { this.settings.MaxDepth }));
            }
            try
            {
                if (!String.IsNullOrEmpty(this.settings.TypeHintName) && (!settings.TypeHintsOnlyWhenNeeded || depth <= 1 || (!Type.Equals(fieldType, type) && !Type.Equals(fieldType, null))))
                {
                    if (appendDelim)
                    {
                        this.WriteObjectPropertyDelim();
                    }
                    else
                    {
                        appendDelim = true;
                    }

                    if (type.Assembly.Equals(Settings.DefaultAssembly))
                    {
                        this.WriteObjectProperty(this.settings.TypeHintName, type.FullName);
                    }
                    else
                    {
                        this.WriteObjectProperty(this.settings.TypeHintName, type.FullName + ", " + type.Assembly.GetName().Name);
                    }
                }


                // Set tag so that other objects can find it when deserializing
                // Note that this must be set after the type hint is serialized
                // To make sure the fields are read correctly when deserializing

                if (referenceHandler != null && referenceHandler.IsHandled(type))
                {
                    if (appendDelim)
                    {
                        this.WriteObjectPropertyDelim();
                    }
                    else
                    {
                        appendDelim = true;
                    }

                    this.WriteObjectProperty("@tag", referenceHandler.GetReferenceID(value));

                    // Notify the reference handler that this value has now been serialized
                    referenceHandler.MarkAsSerialized(value);
                }

                //Console.WriteLine ("Anon " + anonymousType);

                //Console.WriteLine (type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic).Length  + " " + type.GetProperties().Length);

                // serialize public properties

                TypeCoercionUtility.Member[] members;
                this.settings.Coercion.GetMemberWritingMap(type, settings, out members);

                for (int j = 0; j < members.Length; j++)
                {
                    MemberInfo  member = members[j].member;
                    System.Type memberType;
                    object      memberValue;

                    PropertyInfo property = member as PropertyInfo;
                    if (property != null)
                    {
                        memberType  = property.PropertyType;
                        memberValue = property.GetValue(value, null);
                    }
                    else
                    {
                        var field = member as FieldInfo;
                        memberType  = field.FieldType;
                        memberValue = field.GetValue(value);
                    }

                    if (members[j].IsDefaultValue(memberValue))
                    {
                        if (Settings.DebugMode)
                        {
                            Console.WriteLine("Cannot serialize " + member.Name + " : is default value");
                        }
                        continue;
                    }


                    if (appendDelim)
                    {
                        this.WriteObjectPropertyDelim();
                    }
                    else
                    {
                        appendDelim = true;
                    }

                    string name = members[j].name;

                    bool ownedRef = referenceHandler == null || !referenceHandler.IsHandled(memberType) || referenceHandler.IsOwnedRef(member);

                    if (ownedRef || memberValue == null)
                    {
                        // Reference is owned by this member, serialize it as normal
                        this.WriteObjectProperty(name, memberValue, memberType);
                    }
                    else
                    {
                        // Reference is not owned by this property, write a reference to it
                        this.WriteObjectProperty(name, "@" + referenceHandler.GetReferenceID(memberValue), typeof(string));
                    }
                }
            }
            finally
            {
                this.depth--;
            }

            if (appendDelim)
            {
                this.WriteLine();
            }

            this.Writer.Write(JsonReader.OperatorObjectEnd);
        }
        /// <summary>
        /// Determines if the property or field should not be serialized.
        /// </summary>
        /// <param name="objType"></param>
        /// <param name="member"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        /// <remarks>
        /// Checks these in order, if any returns true then this is true:
        /// - is flagged with the JsonIgnoreAttribute property
        /// - has a JsonSpecifiedProperty which returns false
        /// </remarks>
        private bool IsIgnored(Type objType, MemberInfo member, object obj)
        {
            if (JsonIgnoreAttribute.IsJsonIgnore(member))
            {
                return(true);
            }

            string specifiedProperty = JsonSpecifiedPropertyAttribute.GetJsonSpecifiedProperty(member);

            if (!String.IsNullOrEmpty(specifiedProperty))
            {
#if WINDOWS_STORE
                PropertyInfo specProp = TCU.GetTypeInfo(objType).GetRuntimeProperty(specifiedProperty);
#else
                PropertyInfo specProp = TCU.GetTypeInfo(objType).GetProperty(specifiedProperty);
#endif
                if (!PropertyInfo.Equals(specProp, null))
                {
                    object isSpecified = specProp.GetValue(obj, null);
                    if (isSpecified is Boolean && !Convert.ToBoolean(isSpecified))
                    {
                        return(true);
                    }
                }
            }

            //If the class is specified as opt-in serialization only, members must have the JsonMember attribute
            #if WINDOWS_STORE
            if (objType.GetCustomAttribute <JsonOptInAttribute>(true) != null)
            {
                if (member.GetCustomAttribute <JsonMemberAttribute>(true) == null)
                {
                    return(true);
                }
            }
            #else
            if (objType.GetCustomAttributes(typeof(JsonOptInAttribute), true).Length != 0)
            {
                if (member.GetCustomAttributes(typeof(JsonMemberAttribute), true).Length == 0)
                {
                    return(true);
                }
            }
            #endif

            if (this.settings.UseXmlSerializationAttributes)
            {
                if (JsonIgnoreAttribute.IsXmlIgnore(member))
                {
                    return(true);
                }

#if WINDOWS_STORE
                PropertyInfo specProp = TCU.GetTypeInfo(objType).GetRuntimeProperty(specifiedProperty);
#else
                PropertyInfo specProp = TCU.GetTypeInfo(objType).GetProperty(member.Name + "Specified");
#endif

                if (!PropertyInfo.Equals(specProp, null))
                {
                    object isSpecified = specProp.GetValue(obj, null);
                    if (isSpecified is Boolean && !Convert.ToBoolean(isSpecified))
                    {
                        return(true);
                    }
                }
            }

            return(false);
        }
        protected virtual void WriteObject(object value, Type type, bool serializePrivate, Type fieldType = null)
        {
            bool appendDelim = false;

            if (settings.HandleCyclicReferences && !TCU.GetTypeInfo(type).IsValueType)
            {
                int prevIndex = 0;
                if (this.previouslySerializedObjects.TryGetValue(value, out prevIndex))
                {
                    this.Writer.Write(JsonReader.OperatorObjectStart);
                    this.WriteObjectProperty("@ref", prevIndex);
                    this.WriteLine();
                    this.Writer.Write(JsonReader.OperatorObjectEnd);
                    return;
                }
                else
                {
                    this.previouslySerializedObjects.Add(value, this.previouslySerializedObjects.Count);
                }
            }

            this.Writer.Write(JsonReader.OperatorObjectStart);

            this.depth++;
            if (this.depth > this.settings.MaxDepth)
            {
                throw new JsonSerializationException(String.Format(JsonWriter.ErrorMaxDepth, new System.Object[] { this.settings.MaxDepth }));
            }
            try
            {
                if (!String.IsNullOrEmpty(this.settings.TypeHintName) && (!settings.TypeHintsOnlyWhenNeeded || depth <= 1 || (!Type.Equals(fieldType, type) && !Type.Equals(fieldType, null))))
                {
                    if (appendDelim)
                    {
                        this.WriteObjectPropertyDelim();
                    }
                    else
                    {
                        appendDelim = true;
                    }

                    this.WriteObjectProperty(this.settings.TypeHintName, type.FullName + ", " + type.Assembly.GetName().Name);
                }

                //Console.WriteLine ("Anon " + anonymousType);

                //Console.WriteLine (type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic).Length  + " " + type.GetProperties().Length);

                // serialize public properties

                KeyValuePair <string, FieldInfo>[]    fields;
                KeyValuePair <string, PropertyInfo>[] properties;
                this.settings.Coercion.GetMemberWritingMap(type, settings, out fields, out properties);

                for (int j = 0; j < properties.Length; j++)
                {
                    PropertyInfo property = properties [j].Value;

                    object propertyValue = property.GetValue(value, null);
                    if (this.IsDefaultValue(property, propertyValue))
                    {
                        if (Settings.DebugMode)
                        {
                            Console.WriteLine("Cannot serialize " + property.Name + " : is default value");
                        }
                        continue;
                    }


                    if (appendDelim)
                    {
                        this.WriteObjectPropertyDelim();
                    }
                    else
                    {
                        appendDelim = true;
                    }

                    string name = properties [j].Key;

                    this.WriteObjectProperty(name, propertyValue, property.PropertyType);
                }

                for (int j = 0; j < fields.Length; j++)
                {
                    FieldInfo field = fields [j].Value;

                    object fieldValue = field.GetValue(value);
                    if (this.IsDefaultValue(field, fieldValue))
                    {
                        if (Settings.DebugMode)
                        {
                            Console.WriteLine("Cannot serialize " + field.Name + " : is default value");
                        }
                        continue;
                    }

                    if (appendDelim)
                    {
                        this.WriteObjectPropertyDelim();
                    }
                    else
                    {
                        appendDelim = true;
                    }

                    string name = fields [j].Key;

                    this.WriteObjectProperty(name, fieldValue, field.FieldType);
                }

                /*// serialize public fields
                 *              FieldInfo[] fields = TCU.GetTypeInfo(type).GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
                 *              for (int j = 0; j < fields.Length; j++ ) {
                 *                      if (field.IsStatic || (!field.IsPublic &&
                 #if WINDOWS_STORE
                 *                              field.GetCustomAttribute<JsonMemberAttribute>(true) == null))
                 #else
                 *                              field.GetCustomAttributes(typeof(JsonMemberAttribute),true).Length == 0))
                 #endif
                 *                      {
                 #if DEBUG
                 *                              if (Settings.DebugMode)
                 *                                      Console.WriteLine ("Cannot serialize "+field.Name+" : not public or is static (and does not have a JsonMember attribute)");
                 #endif
                 *                              continue;
                 *                      }
                 *
                 *                      if (this.IsIgnored(type, field, value)) {
                 #if DEBUG
                 *                              if (Settings.DebugMode)
                 *                                      Console.WriteLine ("Cannot serialize "+field.Name+" : ignored by settings");
                 #endif
                 *                              continue;
                 *                      }
                 *
                 *                      object fieldValue = field.GetValue(value);
                 *                      if (this.IsDefaultValue(field, fieldValue)) {
                 #if DEBUG
                 *                              if (Settings.DebugMode)
                 *                                      Console.WriteLine ("Cannot serialize "+field.Name+" : is default value");
                 #endif
                 *                              continue;
                 *                      }
                 *
                 *                      if (appendDelim)
                 *                      {
                 *                              this.WriteObjectPropertyDelim();
                 *                              this.WriteLine();
                 *                      } else
                 *                      {
                 *                              appendDelim = true;
                 *                      }
                 *
                 *                      // use Attributes here to control naming
                 *                      string fieldName = JsonNameAttribute.GetJsonName(field);
                 *                      if (String.IsNullOrEmpty(fieldName))
                 *                              fieldName = field.Name;
                 *
                 *                      this.WriteObjectProperty(fieldName, fieldValue, field.FieldType);
                 *              }*/
            } finally
            {
                this.depth--;
            }

            if (appendDelim)
            {
                this.WriteLine();
            }

            this.Writer.Write(JsonReader.OperatorObjectEnd);
        }
Exemple #8
0
 private static bool IsNullable(Type type)
 {
     return(TCU.GetTypeInfo(type).IsGenericType&& (typeof(Nullable <>).Equals(type.GetGenericTypeDefinition())));
 }
Exemple #9
0
        private object CoerceList(Type targetType, Type arrayType, IEnumerable value)
        {
            if (targetType.IsArray)
            {
                return(this.CoerceArray(targetType.GetElementType(), value));
            }

            // targetType serializes as a JSON array but is not an array
            // assume is an ICollection / IEnumerable with AddRange, Add,
            // or custom Constructor with which we can populate it

            // many ICollection types take an IEnumerable or ICollection
            // as a constructor argument.  look through constructors for
            // a compatible match.
            ConstructorInfo[] ctors       = targetType.GetConstructors();
            ConstructorInfo   defaultCtor = null;

            foreach (ConstructorInfo ctor in ctors)
            {
                ParameterInfo[] paramList = ctor.GetParameters();
                if (paramList.Length == 0)
                {
                    // save for in case cannot find closer match
                    defaultCtor = ctor;
                    continue;
                }

                if (paramList.Length == 1 &&
                    TCU.GetTypeInfo(paramList[0].ParameterType).IsAssignableFrom(TCU.GetTypeInfo(arrayType)))
                {
                    try
                    {
                        // invoke first constructor that can take this value as an argument
                        return(ctor.Invoke(
                                   new object[] { value }
                                   ));
                    }
                    catch
                    {
                        // there might exist a better match
                        continue;
                    }
                }
            }

            if (ConstructorInfo.Equals(defaultCtor, null))
            {
                throw new JsonTypeCoercionException(
                          String.Format(TypeCoercionUtility.ErrorDefaultCtor, new System.Object[] { targetType.FullName }));
            }
            object collection;

            try
            {
                // always try-catch Invoke() to expose real exception
                collection = defaultCtor.Invoke(null);
            }
            catch (TargetInvocationException ex)
            {
                if (ex.InnerException != null)
                {
                    throw new JsonTypeCoercionException(ex.InnerException.Message, ex.InnerException);
                }
                throw new JsonTypeCoercionException("Error instantiating " + targetType.FullName, ex);
            }

            // many ICollection types have an AddRange method
            // which adds all items at once
                        #if WINDOWS_STORE
            /** \todo Not sure if this finds the correct methods */
            MethodInfo method = TCU.GetTypeInfo(targetType).GetDeclaredMethod("AddRange");
                        #else
            MethodInfo method = TCU.GetTypeInfo(targetType).GetMethod("AddRange");
                        #endif

            ParameterInfo[] parameters = (MethodInfo.Equals(method, null)) ?
                                         null : method.GetParameters();
            Type paramType = (parameters == null || parameters.Length != 1) ?
                             null : parameters[0].ParameterType;
            if (!Type.Equals(paramType, null) &&
                TCU.GetTypeInfo(paramType).IsAssignableFrom(TCU.GetTypeInfo(arrayType)))
            {
                try
                {
                    // always try-catch Invoke() to expose real exception
                    // add all members in one method
                    method.Invoke(
                        collection,
                        new object[] { value });
                }
                catch (TargetInvocationException ex)
                {
                    if (ex.InnerException != null)
                    {
                        throw new JsonTypeCoercionException(ex.InnerException.Message, ex.InnerException);
                    }
                    throw new JsonTypeCoercionException("Error calling AddRange on " + targetType.FullName, ex);
                }
                return(collection);
            }
            else
            {
                // many ICollection types have an Add method
                // which adds items one at a time
#if WINDOWS_STORE
                /** \todo Not sure if this finds the correct methods */
                method = TCU.GetTypeInfo(targetType).GetDeclaredMethod("Add");
#else
                method = TCU.GetTypeInfo(targetType).GetMethod("Add");
#endif
                parameters = (MethodInfo.Equals(method, null)) ?
                             null : method.GetParameters();
                paramType = (parameters == null || parameters.Length != 1) ?
                            null : parameters[0].ParameterType;
                if (!Type.Equals(paramType, null))
                {
                    // loop through adding items to collection
                    foreach (object item in value)
                    {
                        try {
                            // always try-catch Invoke() to expose real exception
                            method.Invoke(
                                collection,
                                new object[] {
                                this.CoerceType(paramType, item)
                            });
                        } catch (TargetInvocationException ex) {
                            if (ex.InnerException != null)
                            {
                                throw new JsonTypeCoercionException(ex.InnerException.Message, ex.InnerException);
                            }
                            throw new JsonTypeCoercionException("Error calling Add on " + targetType.FullName, ex);
                        }
                    }
                    return(collection);
                }
            }

            try
            {
                // fall back to basics
                return(Convert.ChangeType(value, targetType));
            }
            catch (Exception ex)
            {
                throw new JsonTypeCoercionException(String.Format("Error converting {0} to {1}", new System.Object[] { value.GetType().FullName, targetType.FullName }), ex);
            }
        }
Exemple #10
0
        internal object CoerceType(Type targetType, object value)
        {
            bool isNullable = TypeCoercionUtility.IsNullable(targetType);

            if (value == null)
            {
                if (!allowNullValueTypes &&
                    TCU.GetTypeInfo(targetType).IsValueType&&
                    !isNullable)
                {
                    throw new JsonTypeCoercionException(String.Format(TypeCoercionUtility.ErrorNullValueType, new System.Object[] { targetType.FullName }));
                }
                return(value);
            }

            if (isNullable)
            {
                // nullable types have a real underlying struct
                Type[] genericArgs = targetType.GetGenericArguments();
                if (genericArgs.Length == 1)
                {
                    targetType = genericArgs[0];
                }
            }

            Type actualType = value.GetType();

            if (TCU.GetTypeInfo(targetType).IsAssignableFrom(TCU.GetTypeInfo(actualType)))
            {
                return(value);
            }

            if (TCU.GetTypeInfo(targetType).IsEnum)
            {
                if (value is String)
                {
                    if (!Enum.IsDefined(targetType, value))
                    {
                        // if isn't a defined value perhaps it is the JsonName
                        foreach (FieldInfo field in TCU.GetTypeInfo(targetType).GetFields())
                        {
                            string jsonName = JsonNameAttribute.GetJsonName(field);
                            if (((string)value).Equals(jsonName))
                            {
                                value = field.Name;
                                break;
                            }
                        }
                    }

                    return(Enum.Parse(targetType, (string)value));
                }
                else
                {
                    value = this.CoerceType(Enum.GetUnderlyingType(targetType), value);
                    return(Enum.ToObject(targetType, value));
                }
            }

            // Value is of the wrong type and it has been deserialized as an IDictionary.
            // Previously coercion was supported
            // but this generally just caused more problems than it solved, so type hints are recommended now.
            // More specifically this can cause annoying problems with tags when a tag is referencing some object
            // for which there is no type info for (e.g the field has been removed), that data would have been
            // deserialized as an IDictionary, but when the tag gets the information it will try to coerce it
            // which will often fail horribly
            if (value is IDictionary)
            {
                return(null);
                // Dictionary<string, MemberInfo> memberMap;
                // return this.CoerceType(targetType, (IDictionary)value, out memberMap);
            }

            if (TCU.GetTypeInfo(typeof(IEnumerable)).IsAssignableFrom(TCU.GetTypeInfo(targetType)) &&
                TCU.GetTypeInfo(typeof(IEnumerable)).IsAssignableFrom(TCU.GetTypeInfo(actualType)))
            {
                return(this.CoerceList(targetType, actualType, (IEnumerable)value));
            }

            if (value is String)
            {
                if (Type.Equals(targetType, typeof(DateTime)))
                {
                    DateTime date;
                    if (DateTime.TryParse(
                            (string)value,
                            DateTimeFormatInfo.InvariantInfo,
                            DateTimeStyles.RoundtripKind | DateTimeStyles.AllowWhiteSpaces | DateTimeStyles.NoCurrentDateDefault,
                            out date))
                    {
                        return(date);
                    }
                }
                else if (Type.Equals(targetType, typeof(Guid)))
                {
                    // try-catch is pointless since will throw upon generic conversion
                    return(new Guid((string)value));
                }
                else if (Type.Equals(targetType, typeof(Char)))
                {
                    if (((string)value).Length == 1)
                    {
                        return(((string)value)[0]);
                    }
                }
                else if (Equals(targetType, typeof(Uri)))
                {
                    Uri uri;
                    if (Uri.TryCreate((string)value, UriKind.RelativeOrAbsolute, out uri))
                    {
                        return(uri);
                    }
                }
                else if (Type.Equals(targetType, typeof(Version)))
                {
                    // try-catch is pointless since will throw upon generic conversion
                    return(new Version((string)value));
                }
            }
            else if (Type.Equals(targetType, typeof(TimeSpan)))
            {
                return(new TimeSpan((long)this.CoerceType(typeof(Int64), value)));
            }

#if !WINPHONE_8
            TypeConverter converter = TypeDescriptor.GetConverter(targetType);
            if (converter.CanConvertFrom(actualType))
            {
                return(converter.ConvertFrom(value));
            }

            converter = TypeDescriptor.GetConverter(actualType);
            if (converter.CanConvertTo(targetType))
            {
                return(converter.ConvertTo(value, targetType));
            }
#endif

            try
            {
                // fall back to basics
                return(Convert.ChangeType(value, targetType));
            }
            catch (Exception ex)
            {
                throw new JsonTypeCoercionException(
                          String.Format("Error converting {0} to {1}", new System.Object[] { value.GetType().FullName, targetType.FullName }), ex);
            }
        }
Exemple #11
0
        /** Creates a member map for the type */
        private Dictionary <string, MemberInfo> CreateMemberMap(Type objectType)
        {
            Dictionary <string, MemberInfo> memberMap;

            if (this.MemberMapCache.TryGetValue(objectType, out memberMap))
            {
                // map was stored in cache
                return(memberMap);
            }

            // create a new map
            memberMap = new Dictionary <string, MemberInfo>();

            // load properties into property map
            Type tp = objectType;

            while (tp != null)
            {
                PropertyInfo[] properties = TCU.GetTypeInfo(tp).GetProperties(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
                for (int i = 0; i < properties.Length; i++)
                {
                    PropertyInfo info = properties [i];
                    if (!info.CanRead || !info.CanWrite)
                    {
                        continue;
                    }

                    if (JsonIgnoreAttribute.IsJsonIgnore(info))
                    {
                        continue;
                    }

                    string jsonName = JsonNameAttribute.GetJsonName(info);
                    if (String.IsNullOrEmpty(jsonName))
                    {
                        memberMap[info.Name] = info;
                    }
                    else
                    {
                        memberMap[jsonName] = info;
                    }
                }

                // load public fields into property map
                FieldInfo[] fields = TCU.GetTypeInfo(tp).GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
                foreach (FieldInfo info in fields)
                {
                    if (!info.IsPublic &&
        #if WINDOWS_STORE
                        info.GetCustomAttribute <JsonMemberAttribute>(false) == null
        #else
                        info.GetCustomAttributes(typeof(JsonMemberAttribute), false).Length == 0
        #endif
                        )
                    {
                        continue;
                    }

                    if (JsonIgnoreAttribute.IsJsonIgnore(info))
                    {
                        continue;
                    }

                    string jsonName = JsonNameAttribute.GetJsonName(info);
                    if (String.IsNullOrEmpty(jsonName))
                    {
                        memberMap[info.Name] = info;
                    }
                    else
                    {
                        memberMap[jsonName] = info;
                    }

                    var formerlySerializedAs = info.GetCustomAttributes(typeof(JsonFormerlySerializedAsAttribute), true);
                    if (formerlySerializedAs.Length > 0)
                    {
                        var formerName = (formerlySerializedAs [0] as JsonFormerlySerializedAsAttribute).name;
                        if (!String.IsNullOrEmpty(formerName) && !memberMap.ContainsKey(formerName))
                        {
                            memberMap [formerName] = info;
                        }
                    }
                }

                tp = tp.BaseType;
            }

            // store in cache for repeated usage
            this.MemberMapCache[objectType] = memberMap;

            return(memberMap);
        }
        internal object CoerceType(Type targetType, object value)
        {
            bool isNullable = TypeCoercionUtility.IsNullable(targetType);

            if (value == null)
            {
                if (!allowNullValueTypes &&
                    TCU.GetTypeInfo(targetType).IsValueType&&
                    !isNullable)
                {
                    throw new JsonTypeCoercionException(String.Format(TypeCoercionUtility.ErrorNullValueType, new System.Object[] { targetType.FullName }));
                }
                return(value);
            }

            if (isNullable)
            {
                // nullable types have a real underlying struct
                Type[] genericArgs = targetType.GetGenericArguments();
                if (genericArgs.Length == 1)
                {
                    targetType = genericArgs[0];
                }
            }

            Type actualType = value.GetType();

            if (TCU.GetTypeInfo(targetType).IsAssignableFrom(TCU.GetTypeInfo(actualType)))
            {
                return(value);
            }

            if (TCU.GetTypeInfo(targetType).IsEnum)
            {
                if (value is String)
                {
                    if (!Enum.IsDefined(targetType, value))
                    {
                        // if isn't a defined value perhaps it is the JsonName
                        foreach (FieldInfo field in TCU.GetTypeInfo(targetType).GetFields())
                        {
                            string jsonName = JsonNameAttribute.GetJsonName(field);
                            if (((string)value).Equals(jsonName))
                            {
                                value = field.Name;
                                break;
                            }
                        }
                    }

                    return(Enum.Parse(targetType, (string)value));
                }
                else
                {
                    value = this.CoerceType(Enum.GetUnderlyingType(targetType), value);
                    return(Enum.ToObject(targetType, value));
                }
            }

            if (value is IDictionary)
            {
                Dictionary <string, MemberInfo> memberMap;
                return(this.CoerceType(targetType, (IDictionary)value, out memberMap));
            }

            if (TCU.GetTypeInfo(typeof(IEnumerable)).IsAssignableFrom(TCU.GetTypeInfo(targetType)) &&
                TCU.GetTypeInfo(typeof(IEnumerable)).IsAssignableFrom(TCU.GetTypeInfo(actualType)))
            {
                return(this.CoerceList(targetType, actualType, (IEnumerable)value));
            }

            if (value is String)
            {
                if (Type.Equals(targetType, typeof(DateTime)))
                {
                    DateTime date;
                    if (DateTime.TryParse(
                            (string)value,
                            DateTimeFormatInfo.InvariantInfo,
                            DateTimeStyles.RoundtripKind | DateTimeStyles.AllowWhiteSpaces | DateTimeStyles.NoCurrentDateDefault,
                            out date))
                    {
                        return(date);
                    }
                }
                else if (Type.Equals(targetType, typeof(Guid)))
                {
                    // try-catch is pointless since will throw upon generic conversion
                    return(new Guid((string)value));
                }
                else if (Type.Equals(targetType, typeof(Char)))
                {
                    if (((string)value).Length == 1)
                    {
                        return(((string)value)[0]);
                    }
                }
                else if (Equals(targetType, typeof(Uri)))
                {
                    Uri uri;
                    if (Uri.TryCreate((string)value, UriKind.RelativeOrAbsolute, out uri))
                    {
                        return(uri);
                    }
                }
                else if (Type.Equals(targetType, typeof(Version)))
                {
                    // try-catch is pointless since will throw upon generic conversion
                    return(new Version((string)value));
                }
            }
            else if (Type.Equals(targetType, typeof(TimeSpan)))
            {
                return(new TimeSpan((long)this.CoerceType(typeof(Int64), value)));
            }

#if !WINPHONE_8
            TypeConverter converter = TypeDescriptor.GetConverter(targetType);
            if (converter.CanConvertFrom(actualType))
            {
                return(converter.ConvertFrom(value));
            }

            converter = TypeDescriptor.GetConverter(actualType);
            if (converter.CanConvertTo(targetType))
            {
                return(converter.ConvertTo(value, targetType));
            }
#endif

            try
            {
                // fall back to basics
                return(Convert.ChangeType(value, targetType));
            }
            catch (Exception ex)
            {
                throw new JsonTypeCoercionException(
                          String.Format("Error converting {0} to {1}", new System.Object[] { value.GetType().FullName, targetType.FullName }), ex);
            }
        }