private object CoerceType(Type targetType, IDictionary value, out Dictionary <string, MemberInfo> memberMap)
        {
            object newValue = this.InstantiateObject(targetType, out memberMap);

            if (memberMap != null)
            {
                // copy any values into new object
                foreach (object key in value.Keys)
                {
                    MemberInfo memberInfo;
                    Type       memberType = TypeCoercionUtility.GetMemberInfo(memberMap, key as String, out memberInfo);
                    this.SetMemberValue(newValue, memberType, memberInfo, value[key]);
                }
            }
            return(newValue);
        }
Пример #2
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);
            }
        }