-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:
@@ -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;
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user