-Fixed serializing and deserializing flag enums with EnumMember attribute

-Fixed using a type converter on interfaces
-Fixed deserializing ISerializable objects that also implement IConvertible
-Fixed build
This commit is contained in:
James Newton-King
2013-05-24 19:16:02 +12:00
parent f68794d206
commit 1b63698c02
9 changed files with 592 additions and 63 deletions
@@ -24,8 +24,11 @@
#endregion
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Runtime.Serialization;
using System.Text;
using System.Text.RegularExpressions;
using Newtonsoft.Json.Converters;
#if !NETFX_CORE
@@ -74,6 +77,7 @@ namespace Newtonsoft.Json.Tests.Converters
{
[EnumMember(Value = "@first")]
First,
[EnumMember(Value = "@second")]
Second,
Third
@@ -83,6 +87,7 @@ namespace Newtonsoft.Json.Tests.Converters
{
[EnumMember(Value = "Third")]
First,
[EnumMember(Value = "@second")]
Second,
Third
@@ -100,24 +105,24 @@ namespace Newtonsoft.Json.Tests.Converters
public void NamedEnumDuplicateTest()
{
ExceptionAssert.Throws<Exception>("Enum name 'Third' already exists on enum 'NamedEnumDuplicate'.",
() =>
{
EnumContainer<NamedEnumDuplicate> c = new EnumContainer<NamedEnumDuplicate>
{
Enum = NamedEnumDuplicate.First
};
() =>
{
EnumContainer<NamedEnumDuplicate> c = new EnumContainer<NamedEnumDuplicate>
{
Enum = NamedEnumDuplicate.First
};
JsonConvert.SerializeObject(c, Formatting.Indented, new StringEnumConverter());
});
JsonConvert.SerializeObject(c, Formatting.Indented, new StringEnumConverter());
});
}
[Test]
public void SerializeNameEnumTest()
{
EnumContainer<NamedEnum> c = new EnumContainer<NamedEnum>
{
Enum = NamedEnum.First
};
{
Enum = NamedEnum.First
};
string json = JsonConvert.SerializeObject(c, Formatting.Indented, new StringEnumConverter());
Assert.AreEqual(@"{
@@ -125,9 +130,9 @@ namespace Newtonsoft.Json.Tests.Converters
}", json);
c = new EnumContainer<NamedEnum>
{
Enum = NamedEnum.Third
};
{
Enum = NamedEnum.Third
};
json = JsonConvert.SerializeObject(c, Formatting.Indented, new StringEnumConverter());
Assert.AreEqual(@"{
@@ -179,7 +184,7 @@ namespace Newtonsoft.Json.Tests.Converters
enumClass.NullableStoreColor1 = StoreColor.DarkGoldenrod;
enumClass.NullableStoreColor2 = null;
string json = JsonConvert.SerializeObject(enumClass, Formatting.Indented, new StringEnumConverter { CamelCaseText = true });
string json = JsonConvert.SerializeObject(enumClass, Formatting.Indented, new StringEnumConverter {CamelCaseText = true});
Assert.AreEqual(@"{
""StoreColor"": ""red"",
@@ -192,8 +197,8 @@ namespace Newtonsoft.Json.Tests.Converters
public void SerializeEnumClassUndefined()
{
EnumClass enumClass = new EnumClass();
enumClass.StoreColor = (StoreColor)1000;
enumClass.NullableStoreColor1 = (StoreColor)1000;
enumClass.StoreColor = (StoreColor) 1000;
enumClass.NullableStoreColor1 = (StoreColor) 1000;
enumClass.NullableStoreColor2 = null;
string json = JsonConvert.SerializeObject(enumClass, Formatting.Indented, new StringEnumConverter());
@@ -248,7 +253,7 @@ namespace Newtonsoft.Json.Tests.Converters
NegativeEnumClass negativeEnumClass = JsonConvert.DeserializeObject<NegativeEnumClass>(json, new StringEnumConverter());
Assert.AreEqual(NegativeEnum.Negative, negativeEnumClass.Value1);
Assert.AreEqual((NegativeEnum)int.MinValue, negativeEnumClass.Value2);
Assert.AreEqual((NegativeEnum) int.MinValue, negativeEnumClass.Value2);
}
[Test]
@@ -263,7 +268,7 @@ namespace Newtonsoft.Json.Tests.Converters
EnumClass enumClass = JsonConvert.DeserializeObject<EnumClass>(json, new StringEnumConverter());
Assert.AreEqual(StoreColor.Red | StoreColor.White, enumClass.StoreColor);
Assert.AreEqual((StoreColor)0, enumClass.NullableStoreColor1);
Assert.AreEqual((StoreColor) 0, enumClass.NullableStoreColor1);
Assert.AreEqual(StoreColor.Red | StoreColor.White | StoreColor.Black, enumClass.NullableStoreColor2);
}
@@ -294,8 +299,8 @@ namespace Newtonsoft.Json.Tests.Converters
EnumClass enumClass = JsonConvert.DeserializeObject<EnumClass>(json, new StringEnumConverter());
Assert.AreEqual((StoreColor)1000, enumClass.StoreColor);
Assert.AreEqual((StoreColor)1000, enumClass.NullableStoreColor1);
Assert.AreEqual((StoreColor) 1000, enumClass.StoreColor);
Assert.AreEqual((StoreColor) 1000, enumClass.NullableStoreColor1);
Assert.AreEqual(null, enumClass.NullableStoreColor2);
}
@@ -303,11 +308,11 @@ namespace Newtonsoft.Json.Tests.Converters
public void CamelCaseTextFlagEnumSerialization()
{
EnumContainer<FlagsTestEnum> c = new EnumContainer<FlagsTestEnum>
{
Enum = FlagsTestEnum.First | FlagsTestEnum.Second
};
{
Enum = FlagsTestEnum.First | FlagsTestEnum.Second
};
string json = JsonConvert.SerializeObject(c, Formatting.Indented, new StringEnumConverter { CamelCaseText = true });
string json = JsonConvert.SerializeObject(c, Formatting.Indented, new StringEnumConverter {CamelCaseText = true});
Assert.AreEqual(@"{
""Enum"": ""first, second""
}", json);
@@ -320,7 +325,7 @@ namespace Newtonsoft.Json.Tests.Converters
""Enum"": ""first, second""
}";
EnumContainer<FlagsTestEnum> c = JsonConvert.DeserializeObject<EnumContainer<FlagsTestEnum>>(json, new StringEnumConverter { CamelCaseText = true });
EnumContainer<FlagsTestEnum> c = JsonConvert.DeserializeObject<EnumContainer<FlagsTestEnum>>(json, new StringEnumConverter {CamelCaseText = true});
Assert.AreEqual(FlagsTestEnum.First | FlagsTestEnum.Second, c.Enum);
}
@@ -362,5 +367,84 @@ namespace Newtonsoft.Json.Tests.Converters
Alpha,
Beta,
}
#if !NET20
[Test]
public void EnumMemberPlusFlags()
{
List<Foo> lfoo =
new List<Foo>
{
Foo.Bat | Foo.SerializeAsBaz,
Foo.FooBar,
Foo.Bat,
Foo.SerializeAsBaz,
Foo.FooBar | Foo.SerializeAsBaz,
(Foo) int.MaxValue
};
string json1 = JsonConvert.SerializeObject(lfoo, Formatting.Indented, new StringEnumConverter {CamelCaseText = true});
Assert.AreEqual(@"[
""Bat, baz"",
""foo_bar"",
""Bat"",
""baz"",
""foo_bar, baz"",
2147483647
]", json1);
IList<Foo> foos = JsonConvert.DeserializeObject<List<Foo>>(json1);
Assert.AreEqual(6, foos.Count);
Assert.AreEqual(Foo.Bat | Foo.SerializeAsBaz, foos[0]);
Assert.AreEqual(Foo.FooBar, foos[1]);
Assert.AreEqual(Foo.Bat, foos[2]);
Assert.AreEqual(Foo.SerializeAsBaz, foos[3]);
Assert.AreEqual(Foo.FooBar | Foo.SerializeAsBaz, foos[4]);
Assert.AreEqual((Foo) int.MaxValue, foos[5]);
List<Bar> lbar = new List<Bar>() {Bar.FooBar, Bar.Bat, Bar.SerializeAsBaz};
string json2 = JsonConvert.SerializeObject(lbar, Formatting.Indented, new StringEnumConverter {CamelCaseText = true});
Assert.AreEqual(@"[
""foo_bar"",
""Bat"",
""baz""
]", json2);
IList<Bar> bars = JsonConvert.DeserializeObject<List<Bar>>(json2);
Assert.AreEqual(3, bars.Count);
Assert.AreEqual(Bar.FooBar, bars[0]);
Assert.AreEqual(Bar.Bat, bars[1]);
Assert.AreEqual(Bar.SerializeAsBaz, bars[2]);
}
// Define other methods and classes here
[Flags]
[JsonConverter(typeof (StringEnumConverter))]
private enum Foo
{
[EnumMember(Value = "foo_bar")]
FooBar = 0x01,
Bat = 0x02,
[EnumMember(Value = "baz")]
SerializeAsBaz = 0x4,
};
[JsonConverter(typeof (StringEnumConverter))]
private enum Bar
{
[EnumMember(Value = "foo_bar")]
FooBar,
Bat,
[EnumMember(Value = "baz")]
SerializeAsBaz
};
#endif
}
}
@@ -75,4 +75,4 @@ using System.Security;
// You can specify all the values or you can default the Revision and Build Numbers
// by using the '*' as shown below:
[assembly: AssemblyVersion("4.5.0.0")]
[assembly: AssemblyFileVersion("5.0.5.16119")]
[assembly: AssemblyFileVersion("5.0.5.16124")]
@@ -84,6 +84,7 @@ using System.Linq;
#endif
#if !(SILVERLIGHT || NETFX_CORE)
using System.Drawing;
using System.Diagnostics;
#endif
namespace Newtonsoft.Json.Tests.Serialization
@@ -159,6 +160,22 @@ namespace Newtonsoft.Json.Tests.Serialization
}
}
#if !(NETFX_CORE || PORTABLE || PORTABLE40)
[Test]
public void DeserializeISerializableIConvertible()
{
Ratio ratio = new Ratio(2, 1);
string json = JsonConvert.SerializeObject(ratio);
Assert.AreEqual(@"{""n"":2,""d"":1}", json);
Ratio ratio2 = JsonConvert.DeserializeObject<Ratio>(json);
Assert.AreEqual(ratio.Denominator, ratio2.Denominator);
Assert.AreEqual(ratio.Numerator, ratio2.Numerator);
}
#endif
[Test]
public void SerializeDeserializeRegex()
{
@@ -8846,6 +8863,181 @@ Parameter name: value",
Assert.AreEqual(john, jane.Spouse);
Assert.AreEqual(jane, john.Spouse);
}
#if !(NETFX_CORE || NET35 || NET20 || PORTABLE || PORTABLE40)
[TypeConverter(typeof(MyInterfaceConverter))]
internal interface IMyInterface
{
string Name { get; }
string PrintTest();
}
internal class MyInterfaceConverter : TypeConverter
{
private readonly List<IMyInterface> _writers = new List<IMyInterface>
{
new ConsoleWriter(),
new TraceWriter()
};
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
return destinationType == typeof(string);
}
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
return sourceType == typeof(string);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (value == null)
return null;
return (from w in _writers where w.Name == value.ToString() select w).FirstOrDefault();
}
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value,
Type destinationType)
{
if (value == null)
return null;
return ((IMyInterface)value).Name;
}
}
[TypeConverter(typeof(MyInterfaceConverter))]
internal class ConsoleWriter : IMyInterface
{
public string Name
{
get { return "Console Writer"; }
}
public string PrintTest()
{
return "ConsoleWriter";
}
public override string ToString()
{
return Name;
}
}
internal class TraceWriter : IMyInterface
{
public string Name
{
get { return "Trace Writer"; }
}
public override string ToString()
{
return Name;
}
public string PrintTest()
{
return "TraceWriter";
}
}
internal class TypeConverterJsonConverter : JsonConverter
{
private TypeConverter GetConverter(Type type)
{
var converters = type.GetCustomAttributes(typeof(TypeConverterAttribute), true).Union(
from t in type.GetInterfaces()
from c in t.GetCustomAttributes(typeof(TypeConverterAttribute), true)
select c).Distinct();
return
(from c in converters
let converter =
(TypeConverter)Activator.CreateInstance(Type.GetType(((TypeConverterAttribute)c).ConverterTypeName))
where converter.CanConvertFrom(typeof(string))
&& converter.CanConvertTo(typeof(string))
select converter)
.FirstOrDefault();
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var converter = GetConverter(value.GetType());
var text = converter.ConvertToInvariantString(value);
writer.WriteValue(text);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var converter = GetConverter(objectType);
return converter.ConvertFromInvariantString(reader.Value.ToString());
}
public override bool CanConvert(Type objectType)
{
return GetConverter(objectType) != null;
}
}
[Test]
public void TypeConverterOnInterface()
{
var consoleWriter = new ConsoleWriter();
// If dynamic type handling is enabled, case 1 and 3 work fine
var options = new JsonSerializerSettings
{
Converters = new JsonConverterCollection {new TypeConverterJsonConverter()},
//TypeNameHandling = TypeNameHandling.All
};
//
// Case 1: Serialize the concrete value and restore it from the interface
// Therefore we need dynamic handling of type information if the type is not serialized with the type converter directly
//
var text1 = JsonConvert.SerializeObject(consoleWriter, Formatting.Indented, options);
Assert.AreEqual(@"""Console Writer""", text1);
var restoredWriter = JsonConvert.DeserializeObject<IMyInterface>(text1, options);
Assert.AreEqual("ConsoleWriter", restoredWriter.PrintTest());
//
// Case 2: Serialize a dictionary where the interface is the key
// The key is always serialized with its ToString() method and therefore needs a mechanism to be restored from that (using the type converter)
//
var dict2 = new Dictionary<IMyInterface, string>();
dict2.Add(consoleWriter, "Console");
var text2 = JsonConvert.SerializeObject(dict2, Formatting.Indented, options);
Assert.AreEqual(@"{
""Console Writer"": ""Console""
}", text2);
var restoredObject = JsonConvert.DeserializeObject<Dictionary<IMyInterface, string>>(text2, options);
Assert.AreEqual("ConsoleWriter", restoredObject.First().Key.PrintTest());
//
// Case 3 Serialize a dictionary where the interface is the value
// The key is always serialized with its ToString() method and therefore needs a mechanism to be restored from that (using the type converter)
//
var dict3 = new Dictionary<string, IMyInterface>();
dict3.Add("Console", consoleWriter);
var text3 = JsonConvert.SerializeObject(dict3, Formatting.Indented, options);
Assert.AreEqual(@"{
""Console"": ""Console Writer""
}", text3);
var restoredDict2 = JsonConvert.DeserializeObject<Dictionary<string, IMyInterface>>(text3, options);
Assert.AreEqual("ConsoleWriter", restoredDict2.First().Value.PrintTest());
}
#endif
}
public class PersonReference
@@ -9350,4 +9542,217 @@ Parameter name: value",
UserName = samAccountName.Split('\\')[1];
}
}
#if !NETFX_CORE
public struct Ratio : IConvertible, IFormattable, ISerializable
{
private readonly int _numerator;
private readonly int _denominator;
public Ratio(int numerator, int denominator)
{
_numerator = numerator;
_denominator = denominator;
}
#region Properties
public int Numerator
{
get { return _numerator; }
}
public int Denominator
{
get { return _denominator; }
}
public bool IsNan
{
get { return _denominator == 0; }
}
#endregion
#region Serialization operations
public Ratio(SerializationInfo info, StreamingContext context)
{
_numerator = info.GetInt32("n");
_denominator = info.GetInt32("d");
}
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("n", _numerator);
info.AddValue("d", _denominator);
}
#endregion
#region IConvertible Members
public TypeCode GetTypeCode()
{
return TypeCode.Object;
}
public bool ToBoolean(IFormatProvider provider)
{
return this._numerator == 0;
}
public byte ToByte(IFormatProvider provider)
{
return (byte)(this._numerator / this._denominator);
}
public char ToChar(IFormatProvider provider)
{
return Convert.ToChar(this._numerator / this._denominator);
}
public DateTime ToDateTime(IFormatProvider provider)
{
return Convert.ToDateTime(this._numerator / this._denominator);
}
public decimal ToDecimal(IFormatProvider provider)
{
return (decimal)this._numerator / this._denominator;
}
public double ToDouble(IFormatProvider provider)
{
return this._denominator == 0
? double.NaN
: (double)this._numerator / this._denominator;
}
public short ToInt16(IFormatProvider provider)
{
return (short)(this._numerator / this._denominator);
}
public int ToInt32(IFormatProvider provider)
{
return this._numerator / this._denominator;
}
public long ToInt64(IFormatProvider provider)
{
return this._numerator / this._denominator;
}
public sbyte ToSByte(IFormatProvider provider)
{
return (sbyte)(this._numerator / this._denominator);
}
public float ToSingle(IFormatProvider provider)
{
return this._denominator == 0
? float.NaN
: (float)this._numerator / this._denominator;
}
public string ToString(IFormatProvider provider)
{
return this._denominator == 1
? this._numerator.ToString(provider)
: this._numerator.ToString(provider) + "/" + this._denominator.ToString(provider);
}
public object ToType(Type conversionType, IFormatProvider provider)
{
return Convert.ChangeType(ToDouble(provider), conversionType, provider);
}
public ushort ToUInt16(IFormatProvider provider)
{
return (ushort)(this._numerator / this._denominator);
}
public uint ToUInt32(IFormatProvider provider)
{
return (uint)(this._numerator / this._denominator);
}
public ulong ToUInt64(IFormatProvider provider)
{
return (ulong)(this._numerator / this._denominator);
}
#endregion
#region String operations
public override string ToString()
{
return ToString(CultureInfo.InvariantCulture);
}
public string ToString(string format, IFormatProvider formatProvider)
{
return ToString(CultureInfo.InvariantCulture);
}
public static Ratio Parse(string input)
{
return Parse(input, CultureInfo.InvariantCulture);
}
public static Ratio Parse(string input, IFormatProvider formatProvider)
{
Ratio result;
if (!TryParse(input, formatProvider, out result))
{
throw new FormatException(
string.Format(
CultureInfo.InvariantCulture,
"Text '{0}' is invalid text representation of ratio",
input));
}
return result;
}
public static bool TryParse(string input, out Ratio result)
{
return TryParse(input, CultureInfo.InvariantCulture, out result);
}
public static bool TryParse(string input, IFormatProvider formatProvider, out Ratio result)
{
if (input != null)
{
var fractionIndex = input.IndexOf('/');
int numerator;
if (fractionIndex < 0)
{
if (int.TryParse(input, NumberStyles.Integer, formatProvider, out numerator))
{
result = new Ratio(numerator, 1);
return true;
}
}
else
{
int denominator;
if (int.TryParse(input.Substring(0, fractionIndex), NumberStyles.Integer, formatProvider, out numerator) &&
int.TryParse(input.Substring(fractionIndex + 1), NumberStyles.Integer, formatProvider, out denominator))
{
result = new Ratio(numerator, denominator);
return true;
}
}
}
result = default(Ratio);
return false;
}
#endregion
}
#endif
}
@@ -77,17 +77,24 @@ namespace Newtonsoft.Json.Converters
{
BidirectionalDictionary<string, string> map = GetEnumNameMap(e.GetType());
string resolvedEnumName;
map.TryGetByFirst(enumName, out resolvedEnumName);
resolvedEnumName = resolvedEnumName ?? enumName;
if (CamelCaseText)
string[] names = enumName.Split(',');
for (int i = 0; i < names.Length; i++)
{
string[] names = resolvedEnumName.Split(',').Select(item => StringUtils.ToCamelCase(item.Trim())).ToArray();
resolvedEnumName = string.Join(", ", names);
string name = names[i].Trim();
string resolvedEnumName;
map.TryGetByFirst(name, out resolvedEnumName);
resolvedEnumName = resolvedEnumName ?? name;
if (CamelCaseText)
resolvedEnumName = StringUtils.ToCamelCase(resolvedEnumName);
names[i] = resolvedEnumName;
}
writer.WriteValue(resolvedEnumName);
string finalName = string.Join(", ", names);
writer.WriteValue(finalName);
}
}
@@ -120,12 +127,27 @@ namespace Newtonsoft.Json.Converters
if (enumText == string.Empty && isNullable)
return null;
var map = GetEnumNameMap(t);
string resolvedEnumName;
map.TryGetBySecond(enumText, out resolvedEnumName);
resolvedEnumName = resolvedEnumName ?? enumText;
string finalEnumText;
return Enum.Parse(t, resolvedEnumName, true);
BidirectionalDictionary<string, string> map = GetEnumNameMap(t);
if (enumText.IndexOf(',') != -1)
{
string[] names = enumText.Split(',');
for (int i = 0; i < names.Length; i++)
{
string name = names[i].Trim();
names[i] = ResolvedEnumName(map, name);
}
finalEnumText = string.Join(", ", names);
}
else
{
finalEnumText = ResolvedEnumName(map, enumText);
}
return Enum.Parse(t, finalEnumText, true);
}
if (reader.TokenType == JsonToken.Integer)
@@ -140,6 +162,14 @@ namespace Newtonsoft.Json.Converters
throw JsonSerializationException.Create(reader, "Unexpected token when parsing enum. Expected String or Integer, got {0}.".FormatWith(CultureInfo.InvariantCulture, reader.TokenType));
}
private static string ResolvedEnumName(BidirectionalDictionary<string, string> map, string enumText)
{
string resolvedEnumName;
map.TryGetBySecond(enumText, out resolvedEnumName);
resolvedEnumName = resolvedEnumName ?? enumText;
return resolvedEnumName;
}
private BidirectionalDictionary<string, string> GetEnumNameMap(Type t)
{
BidirectionalDictionary<string, string> map;
-18
View File
@@ -490,24 +490,6 @@ namespace Newtonsoft.Json
throw new ArgumentException("Unsupported type: {0}. Use the JsonSerializer class to get the object's JSON representation.".FormatWith(CultureInfo.InvariantCulture, value.GetType()));
}
internal static bool IsJsonPrimitiveType(Type t)
{
PrimitiveTypeCode typeCode = ConvertUtils.GetTypeCode(t);
if (typeCode != PrimitiveTypeCode.Empty && typeCode != PrimitiveTypeCode.Object)
return true;
#if !(PORTABLE || NETFX_CORE)
if (typeof(IConvertible).IsAssignableFrom(t)
|| (ReflectionUtils.IsNullableType(t) && typeof(IConvertible).IsAssignableFrom(Nullable.GetUnderlyingType(t))))
{
return !typeof(JToken).IsAssignableFrom(t);
}
#endif
return false;
}
#region Serialize
/// <summary>
/// Serializes the specified object to a JSON string.
@@ -251,6 +251,8 @@
<Compile Include="Serialization\ReflectionValueProvider.cs" />
<Compile Include="Serialization\DiagnosticsTraceWriter.cs" />
<Compile Include="Serialization\MemoryTraceWriter.cs" />
<Compile Include="Serialization\TraceJsonReader.cs" />
<Compile Include="Serialization\TraceJsonWriter.cs" />
<Compile Include="StreamingContext.cs" />
<Compile Include="StringEscapeHandling.cs" />
<Compile Include="TraceLevel.cs" />
@@ -92,6 +92,6 @@ using System.Security;
// You can specify all the values or you can default the Revision and Build Numbers
// by using the '*' as shown below:
[assembly: AssemblyVersion("4.5.0.0")]
[assembly: AssemblyFileVersion("5.0.5.16119")]
[assembly: AssemblyFileVersion("5.0.5.16124")]
[assembly: CLSCompliant(true)]
@@ -844,7 +844,7 @@ namespace Newtonsoft.Json.Serialization
{
Type t = ReflectionUtils.EnsureNotNullableType(objectType);
if (JsonConvert.IsJsonPrimitiveType(objectType))
if (IsJsonPrimitiveType(objectType))
return CreatePrimitiveContract(objectType);
if (JsonTypeReflector.GetJsonObjectAttribute(t) != null)
@@ -878,9 +878,35 @@ namespace Newtonsoft.Json.Serialization
return CreateDynamicContract(objectType);
#endif
#if !(PORTABLE || NETFX_CORE)
// tested last because it is not possible to automatically deserialize custom IConvertible types
if (IsIConvertible(t))
return CreatePrimitiveContract(t);
#endif
return CreateObjectContract(objectType);
}
internal static bool IsJsonPrimitiveType(Type t)
{
PrimitiveTypeCode typeCode = ConvertUtils.GetTypeCode(t);
return (typeCode != PrimitiveTypeCode.Empty && typeCode != PrimitiveTypeCode.Object);
}
#if !(PORTABLE || NETFX_CORE)
internal static bool IsIConvertible(Type t)
{
if (typeof(IConvertible).IsAssignableFrom(t)
|| (ReflectionUtils.IsNullableType(t) && typeof(IConvertible).IsAssignableFrom(Nullable.GetUnderlyingType(t))))
{
return !typeof(JToken).IsAssignableFrom(t);
}
return false;
}
#endif
internal static bool CanConvertToString(Type type)
{
#if !(NETFX_CORE || PORTABLE40 || PORTABLE)
@@ -407,9 +407,6 @@ namespace Newtonsoft.Json.Utilities
return FromBigInteger((BigInteger)initialValue, targetType);
#endif
if (targetType.IsInterface() || targetType.IsGenericTypeDefinition() || targetType.IsAbstract())
throw new ArgumentException("Target type {0} is not a value type or a non-abstract class.".FormatWith(CultureInfo.InvariantCulture, targetType), "targetType");
#if !(NETFX_CORE || PORTABLE40 || PORTABLE)
// see if source or target types have a TypeConverter that converts between the two
TypeConverter toConverter = GetConverter(initialType);
@@ -449,6 +446,9 @@ namespace Newtonsoft.Json.Utilities
return EnsureTypeAssignable(ToValue((INullable)initialValue), initialType, targetType);
#endif
if (targetType.IsInterface() || targetType.IsGenericTypeDefinition() || targetType.IsAbstract())
throw new ArgumentException("Target type {0} is not a value type or a non-abstract class.".FormatWith(CultureInfo.InvariantCulture, targetType), "targetType");
throw new InvalidOperationException("Can not convert from {0} to {1}.".FormatWith(CultureInfo.InvariantCulture, initialType, targetType));
}