-Added support for TypeConverters to netstandard1.0+

This commit is contained in:
James Newton-King
2017-01-19 17:43:07 +13:00
parent 55afb9aa72
commit 2e7b24e9b1
13 changed files with 161 additions and 48 deletions
@@ -240,7 +240,7 @@ namespace Newtonsoft.Json.Tests
{
var json = System.IO.File.ReadAllText("large.json");
BenchmarkDeserializeMethod<IList<RootObject>>(SerializeMethod.JsonNet, json, Iterations / 10, false);
BenchmarkDeserializeMethod<IList<RootObject>>(SerializeMethod.JsonNet, json, Math.Min(Iterations, 10), false);
}
[Test]
@@ -9089,6 +9089,119 @@ This is just junk, though.";
}
#endif
#if !(PORTABLE || PORTABLE40 || DNXCORE50) || NETSTANDARD1_0 || NETSTANDARD1_1
[Test]
public void SerializeDictionaryWithStructKey_Custom()
{
string json = JsonConvert.SerializeObject(
new Dictionary<TypeConverterSize, TypeConverterSize> { { new TypeConverterSize(1, 2), new TypeConverterSize(3, 4) } }
);
Assert.AreEqual(@"{""1, 2"":""3, 4""}", json);
Dictionary<TypeConverterSize, TypeConverterSize> d = JsonConvert.DeserializeObject<Dictionary<TypeConverterSize, TypeConverterSize>>(json);
Assert.AreEqual(new TypeConverterSize(1, 2), d.Keys.First());
Assert.AreEqual(new TypeConverterSize(3, 4), d.Values.First());
}
[TypeConverter(typeof(TypeConverterSizeConverter))]
public struct TypeConverterSize
{
public static readonly TypeConverterSize Empty;
private int _width;
private int _height;
public TypeConverterSize(int width, int height)
{
_width = width;
_height = height;
}
public int Width
{
get { return _width; }
set { _width = value; }
}
public int Height
{
get { return _height; }
set { _height = value; }
}
}
public class TypeConverterSizeConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
return ((sourceType == typeof(string)) || base.CanConvertFrom(context, sourceType));
}
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
return base.CanConvertTo(context, destinationType);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
string str = value as string;
if (str == null)
{
return base.ConvertFrom(context, culture, value);
}
string str2 = str.Trim();
if (str2.Length == 0)
{
return null;
}
if (culture == null)
{
culture = CultureInfo.CurrentCulture;
}
string[] strArray = str2.Split(',');
int[] numArray = new int[strArray.Length];
TypeConverter converter = TypeDescriptor.GetConverter(typeof(int));
for (int i = 0; i < numArray.Length; i++)
{
numArray[i] = (int)converter.ConvertFromString(context, culture, strArray[i]);
}
if (numArray.Length == 2)
{
return new TypeConverterSize(numArray[0], numArray[1]);
}
throw new ArgumentException("Bad format.");
}
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
{
if (destinationType == null)
{
throw new ArgumentNullException("destinationType");
}
if (value is TypeConverterSize)
{
if (destinationType == typeof(string))
{
TypeConverterSize size = (TypeConverterSize)value;
if (culture == null)
{
culture = CultureInfo.CurrentCulture;
}
TypeConverter converter = TypeDescriptor.GetConverter(typeof(int));
string[] strArray = new string[2];
int num = 0;
strArray[num++] = converter.ConvertToString(context, culture, size.Width);
strArray[num++] = converter.ConvertToString(context, culture, size.Height);
return string.Join(", ", strArray);
}
}
return base.ConvertTo(context, culture, value, destinationType);
}
}
#endif
[Test]
public void DeserializeCustomReferenceResolver()
{
+1
View File
@@ -95,6 +95,7 @@
"System.Xml.XmlSerializer": "4.0.11",
"System.Runtime.Serialization.Json": "4.0.2",
"System.Runtime.Serialization.Xml": "4.1.1",
"System.ComponentModel.TypeConverter": "4.1.0",
"xunit": "2.1.0",
"dotnet-test-xunit": "2.2.0-preview2-build1029"
},
@@ -43,7 +43,7 @@
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
<DefineConstants>NET20;HAVE_ADO_NET;HAVE_APP_DOMAIN;HAVE_BINARY_SERIALIZATION;HAVE_CAS;HAVE_CHAR_TO_LOWER_WITH_CULTURE;HAVE_CHAR_TO_STRING_WITH_CULTURE;HAVE_COM_ATTRIBUTES;HAVE_COMPONENT_MODEL;HAVE_DB_NULL_TYPE_CODE;HAVE_EMPTY_TYPES;HAVE_FULL_REFLECTION;HAVE_ICLONEABLE;HAVE_ICONVERTIBLE;HAVE_MEMORY_BARRIER;
HAVE_NON_SERIALIZED_ATTRIBUTE;HAVE_REFLECTION_EMIT;HAVE_STREAM_READER_WRITER_CLOSE;HAVE_TRACE_WRITER;HAVE_UNICODE_SURROGATE_DETECTION;HAVE_XML_DOCUMENT</DefineConstants>
HAVE_NON_SERIALIZED_ATTRIBUTE;HAVE_REFLECTION_EMIT;HAVE_STREAM_READER_WRITER_CLOSE;HAVE_TRACE_WRITER;HAVE_TYPE_DESCRIPTOR;HAVE_UNICODE_SURROGATE_DETECTION;HAVE_XML_DOCUMENT</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -44,7 +44,7 @@
<BootstrapperEnabled>true</BootstrapperEnabled>
<TargetFrameworkProfile>
</TargetFrameworkProfile>
<DefineConstants>NET35;HAVE_ADO_NET;HAVE_APP_DOMAIN;HAVE_BINARY_SERIALIZATION;HAVE_CAS;HAVE_CHAR_TO_STRING_WITH_CULTURE;HAVE_CHAR_TO_LOWER_WITH_CULTURE;HAVE_COM_ATTRIBUTES;HAVE_COMPONENT_MODEL;HAVE_DATA_CONTRACTS;HAVE_DATE_TIME_OFFSET;HAVE_DB_NULL_TYPE_CODE;HAVE_EMPTY_TYPES;HAVE_ENTITY_FRAMEWORK;HAVE_FULL_REFLECTION;HAVE_HASH_SET;HAVE_ICLONEABLE;HAVE_ICONVERTIBLE;HAVE_INOTIFY_PROPERTY_CHANGING;HAVE_LINQ;HAVE_MEMORY_BARRIER; HAVE_NON_SERIALIZED_ATTRIBUTE;HAVE_REFLECTION_EMIT;HAVE_STREAM_READER_WRITER_CLOSE;HAVE_TIME_ZONE_INFO;HAVE_TRACE_WRITER;HAVE_UNICODE_SURROGATE_DETECTION;HAVE_XLINQ;HAVE_XML_DOCUMENT</DefineConstants>
<DefineConstants>NET35;HAVE_ADO_NET;HAVE_APP_DOMAIN;HAVE_BINARY_SERIALIZATION;HAVE_CAS;HAVE_CHAR_TO_STRING_WITH_CULTURE;HAVE_CHAR_TO_LOWER_WITH_CULTURE;HAVE_COM_ATTRIBUTES;HAVE_COMPONENT_MODEL;HAVE_DATA_CONTRACTS;HAVE_DATE_TIME_OFFSET;HAVE_DB_NULL_TYPE_CODE;HAVE_EMPTY_TYPES;HAVE_ENTITY_FRAMEWORK;HAVE_FULL_REFLECTION;HAVE_HASH_SET;HAVE_ICLONEABLE;HAVE_ICONVERTIBLE;HAVE_INOTIFY_PROPERTY_CHANGING;HAVE_LINQ;HAVE_MEMORY_BARRIER;HAVE_NON_SERIALIZED_ATTRIBUTE;HAVE_REFLECTION_EMIT;HAVE_STREAM_READER_WRITER_CLOSE;HAVE_TIME_ZONE_INFO;HAVE_TRACE_WRITER;HAVE_TYPE_DESCRIPTOR;HAVE_UNICODE_SURROGATE_DETECTION;HAVE_XLINQ;HAVE_XML_DOCUMENT</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -44,7 +44,7 @@
<BootstrapperEnabled>true</BootstrapperEnabled>
<TargetFrameworkProfile>
</TargetFrameworkProfile>
<DefineConstants>NET40;HAVE_ADO_NET;HAVE_APP_DOMAIN;HAVE_BIG_INTEGER;HAVE_BINARY_SERIALIZATION;HAVE_CAS;HAVE_CHAR_TO_STRING_WITH_CULTURE;HAVE_CHAR_TO_LOWER_WITH_CULTURE;HAVE_COM_ATTRIBUTES;HAVE_COMPONENT_MODEL;HAVE_CONCURRENT_COLLECTIONS;HAVE_COVARIANT_GENERICS;HAVE_DATA_CONTRACTS;HAVE_DATE_TIME_OFFSET;HAVE_DB_NULL_TYPE_CODE;HAVE_DYNAMIC;HAVE_EMPTY_TYPES;HAVE_ENTITY_FRAMEWORK;HAVE_EXPRESSIONS;HAVE_FSHARP_TYPES;HAVE_FULL_REFLECTION;HAVE_GUID_TRY_PARSE;HAVE_HASH_SET;HAVE_ICLONEABLE;HAVE_ICONVERTIBLE;HAVE_IGNORE_DATA_MEMBER_ATTRIBUTE;HAVE_INOTIFY_COLLECTION_CHANGED;HAVE_INOTIFY_PROPERTY_CHANGING;HAVE_ISET;HAVE_LINQ;HAVE_MEMORY_BARRIER;HAVE_NON_SERIALIZED_ATTRIBUTE;HAVE_REFLECTION_EMIT;HAVE_SECURITY_SAFE_CRITICAL_ATTRIBUTE;HAVE_SERIALIZATION_BINDER_BIND_TO_NAME;HAVE_STREAM_READER_WRITER_CLOSE;HAVE_STRING_JOIN_WITH_ENUMERABLE;HAVE_TIME_SPAN_PARSE_WITH_CULTURE;HAVE_TIME_SPAN_TO_STRING_WITH_CULTURE;HAVE_TIME_ZONE_INFO;HAVE_TPL;HAVE_TRACE_WRITER;HAVE_UNICODE_SURROGATE_DETECTION;HAVE_VARIANT_TYPE_PARAMETERS;HAVE_VERSION_TRY_PARSE;HAVE_XLINQ;HAVE_XML_DOCUMENT</DefineConstants>
<DefineConstants>NET40;HAVE_ADO_NET;HAVE_APP_DOMAIN;HAVE_BIG_INTEGER;HAVE_BINARY_SERIALIZATION;HAVE_CAS;HAVE_CHAR_TO_STRING_WITH_CULTURE;HAVE_CHAR_TO_LOWER_WITH_CULTURE;HAVE_COM_ATTRIBUTES;HAVE_COMPONENT_MODEL;HAVE_CONCURRENT_COLLECTIONS;HAVE_COVARIANT_GENERICS;HAVE_DATA_CONTRACTS;HAVE_DATE_TIME_OFFSET;HAVE_DB_NULL_TYPE_CODE;HAVE_DYNAMIC;HAVE_EMPTY_TYPES;HAVE_ENTITY_FRAMEWORK;HAVE_EXPRESSIONS;HAVE_FSHARP_TYPES;HAVE_FULL_REFLECTION;HAVE_GUID_TRY_PARSE;HAVE_HASH_SET;HAVE_ICLONEABLE;HAVE_ICONVERTIBLE;HAVE_IGNORE_DATA_MEMBER_ATTRIBUTE;HAVE_INOTIFY_COLLECTION_CHANGED;HAVE_INOTIFY_PROPERTY_CHANGING;HAVE_ISET;HAVE_LINQ;HAVE_MEMORY_BARRIER;HAVE_NON_SERIALIZED_ATTRIBUTE;HAVE_REFLECTION_EMIT;HAVE_SECURITY_SAFE_CRITICAL_ATTRIBUTE;HAVE_SERIALIZATION_BINDER_BIND_TO_NAME;HAVE_STREAM_READER_WRITER_CLOSE;HAVE_STRING_JOIN_WITH_ENUMERABLE;HAVE_TIME_SPAN_PARSE_WITH_CULTURE;HAVE_TIME_SPAN_TO_STRING_WITH_CULTURE;HAVE_TIME_ZONE_INFO;HAVE_TPL;HAVE_TRACE_WRITER;HAVE_TYPE_DESCRIPTOR;HAVE_UNICODE_SURROGATE_DETECTION;HAVE_VARIANT_TYPE_PARAMETERS;HAVE_VERSION_TRY_PARSE;HAVE_XLINQ;HAVE_XML_DOCUMENT</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
+1 -2
View File
@@ -11,8 +11,7 @@
<AssemblyName>Newtonsoft.Json</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<DefineConstants>HAVE_ADO_NET;HAVE_APP_DOMAIN;HAVE_ASYNC;HAVE_BIG_INTEGER;HAVE_BINARY_SERIALIZATION;HAVE_CAS;HAVE_CHAR_TO_LOWER_WITH_CULTURE;HAVE_CHAR_TO_STRING_WITH_CULTURE;HAVE_COM_ATTRIBUTES;HAVE_COMPONENT_MODEL;HAVE_CONCURRENT_COLLECTIONS;HAVE_COVARIANT_GENERICS;HAVE_DATA_CONTRACTS;HAVE_DATE_TIME_OFFSET;HAVE_DB_NULL_TYPE_CODE;HAVE_DYNAMIC;HAVE_EMPTY_TYPES;HAVE_ENTITY_FRAMEWORK;HAVE_EXPRESSIONS;HAVE_FSHARP_TYPES;HAVE_FULL_REFLECTION;HAVE_GUID_TRY_PARSE;HAVE_HASH_SET;HAVE_ICLONEABLE;HAVE_ICONVERTIBLE;HAVE_IGNORE_DATA_MEMBER_ATTRIBUTE;HAVE_IMMUTABLE_COLLECTIONS;HAVE_INOTIFY_COLLECTION_CHANGED;HAVE_INOTIFY_PROPERTY_CHANGING;HAVE_ISET;HAVE_LINQ;HAVE_MEMORY_BARRIER;HAVE_METHOD_IMPL_ATTRIBUTE;
HAVE_NON_SERIALIZED_ATTRIBUTE;HAVE_READ_ONLY_COLLECTIONS;HAVE_REFLECTION_EMIT;HAVE_SECURITY_SAFE_CRITICAL_ATTRIBUTE;HAVE_SERIALIZATION_BINDER_BIND_TO_NAME;HAVE_STREAM_READER_WRITER_CLOSE;HAVE_STRING_JOIN_WITH_ENUMERABLE;HAVE_TIME_SPAN_PARSE_WITH_CULTURE;HAVE_TIME_SPAN_TO_STRING_WITH_CULTURE;HAVE_TIME_ZONE_INFO;HAVE_TPL;HAVE_TRACE_WRITER;HAVE_UNICODE_SURROGATE_DETECTION;HAVE_VARIANT_TYPE_PARAMETERS;HAVE_VERSION_TRY_PARSE;HAVE_XLINQ;HAVE_XML_DOCUMENT</DefineConstants>
<DefineConstants>HAVE_ADO_NET;HAVE_APP_DOMAIN;HAVE_ASYNC;HAVE_BIG_INTEGER;HAVE_BINARY_SERIALIZATION;HAVE_CAS;HAVE_CHAR_TO_LOWER_WITH_CULTURE;HAVE_CHAR_TO_STRING_WITH_CULTURE;HAVE_COM_ATTRIBUTES;HAVE_COMPONENT_MODEL;HAVE_CONCURRENT_COLLECTIONS;HAVE_COVARIANT_GENERICS;HAVE_DATA_CONTRACTS;HAVE_DATE_TIME_OFFSET;HAVE_DB_NULL_TYPE_CODE;HAVE_DYNAMIC;HAVE_EMPTY_TYPES;HAVE_ENTITY_FRAMEWORK;HAVE_EXPRESSIONS;HAVE_FSHARP_TYPES;HAVE_FULL_REFLECTION;HAVE_GUID_TRY_PARSE;HAVE_HASH_SET;HAVE_ICLONEABLE;HAVE_ICONVERTIBLE;HAVE_IGNORE_DATA_MEMBER_ATTRIBUTE;HAVE_IMMUTABLE_COLLECTIONS;HAVE_INOTIFY_COLLECTION_CHANGED;HAVE_INOTIFY_PROPERTY_CHANGING;HAVE_ISET;HAVE_LINQ;HAVE_MEMORY_BARRIER;HAVE_METHOD_IMPL_ATTRIBUTE;HAVE_NON_SERIALIZED_ATTRIBUTE;HAVE_READ_ONLY_COLLECTIONS;HAVE_REFLECTION_EMIT;HAVE_SECURITY_SAFE_CRITICAL_ATTRIBUTE;HAVE_SERIALIZATION_BINDER_BIND_TO_NAME;HAVE_STREAM_READER_WRITER_CLOSE;HAVE_STRING_JOIN_WITH_ENUMERABLE;HAVE_TIME_SPAN_PARSE_WITH_CULTURE;HAVE_TIME_SPAN_TO_STRING_WITH_CULTURE;HAVE_TIME_ZONE_INFO;HAVE_TPL;HAVE_TRACE_WRITER;HAVE_TYPE_DESCRIPTOR;HAVE_UNICODE_SURROGATE_DETECTION;HAVE_VARIANT_TYPE_PARAMETERS;HAVE_VERSION_TRY_PARSE;HAVE_XLINQ;HAVE_XML_DOCUMENT</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -1233,19 +1233,11 @@ namespace Newtonsoft.Json.Serialization
internal static bool CanConvertToString(Type type)
{
#if HAVE_COMPONENT_MODEL
TypeConverter converter = ConvertUtils.GetConverter(type);
// use the objectType's TypeConverter if it has one and can convert to a string
if (converter != null
&& !(converter is ComponentConverter)
&& !(converter is ReferenceConverter)
&& converter.GetType() != typeof(TypeConverter))
#if HAVE_TYPE_DESCRIPTOR
TypeConverter converter;
if (JsonTypeReflector.CanTypeDescriptorConvertString(type, out converter))
{
if (converter.CanConvertTo(typeof(string)))
{
return true;
}
return true;
}
#endif
@@ -379,19 +379,12 @@ namespace Newtonsoft.Json.Serialization
internal static bool TryConvertToString(object value, Type type, out string s)
{
#if HAVE_COMPONENT_MODEL
TypeConverter converter = ConvertUtils.GetConverter(type);
// use the objectType's TypeConverter if it has one and can convert to a string
if (converter != null
&& !(converter is ComponentConverter)
&& converter.GetType() != typeof(TypeConverter))
#if HAVE_TYPE_DESCRIPTOR
TypeConverter converter;
if (JsonTypeReflector.CanTypeDescriptorConvertString(type, out converter))
{
if (converter.CanConvertTo(typeof(string)))
{
s = converter.ConvertToInvariantString(value);
return true;
}
s = converter.ConvertToInvariantString(value);
return true;
}
#endif
@@ -69,6 +69,29 @@ namespace Newtonsoft.Json.Serialization
return CachedAttributeGetter<T>.GetAttribute(attributeProvider);
}
#if HAVE_TYPE_DESCRIPTOR
public static bool CanTypeDescriptorConvertString(Type type, out TypeConverter typeConverter)
{
typeConverter = TypeDescriptor.GetConverter(type);
// use the objectType's TypeConverter if it has one and can convert to a string
if (typeConverter != null)
{
Type converterType = typeConverter.GetType();
if (converterType.FullName != "System.ComponentModel.ComponentConverter"
&& converterType.FullName != "System.ComponentModel.ReferenceConverter"
&& converterType != typeof(TypeConverter))
{
return typeConverter.CanConvertTo(typeof(string));
}
}
return false;
}
#endif
#if HAVE_DATA_CONTRACTS
public static DataContractAttribute GetDataContractAttribute(Type type)
{
@@ -245,13 +268,6 @@ namespace Newtonsoft.Json.Serialization
};
}
#if HAVE_COMPONENT_MODEL
public static TypeConverter GetTypeConverter(Type type)
{
return TypeDescriptor.GetConverter(type);
}
#endif
#if !(NET20 || DOTNET)
private static Type GetAssociatedMetadataType(Type type)
{
+4 -11
View File
@@ -559,9 +559,9 @@ namespace Newtonsoft.Json.Utilities
}
#endif
#if HAVE_COMPONENT_MODEL
#if HAVE_TYPE_DESCRIPTOR
// see if source or target types have a TypeConverter that converts between the two
TypeConverter toConverter = GetConverter(initialType);
TypeConverter toConverter = TypeDescriptor.GetConverter(initialType);
if (toConverter != null && toConverter.CanConvertTo(targetType))
{
@@ -569,7 +569,7 @@ namespace Newtonsoft.Json.Utilities
return ConvertResult.Success;
}
TypeConverter fromConverter = GetConverter(targetType);
TypeConverter fromConverter = TypeDescriptor.GetConverter(targetType);
if (fromConverter != null && fromConverter.CanConvertFrom(initialType))
{
@@ -707,19 +707,12 @@ namespace Newtonsoft.Json.Utilities
}
#endif
#if HAVE_COMPONENT_MODEL
internal static TypeConverter GetConverter(Type t)
{
return JsonTypeReflector.GetTypeConverter(t);
}
#endif
public static bool VersionTryParse(string input, out Version result)
{
#if HAVE_VERSION_TRY_PARSE
return Version.TryParse(input, out result);
#else
// improve failure performance with regex?
// improve failure performance with regex?
try
{
result = new Version(input);
+4
View File
@@ -172,6 +172,7 @@
"HAVE_TIME_SPAN_TO_STRING_WITH_CULTURE",
"HAVE_TIME_ZONE_INFO",
"HAVE_TPL",
"HAVE_TYPE_DESCRIPTOR",
"HAVE_UNICODE_SURROGATE_DETECTION",
"HAVE_VARIANT_TYPE_PARAMETERS",
"HAVE_VERSION_TRY_PARSE",
@@ -181,6 +182,7 @@
"dependencies": {
"Microsoft.CSharp": "4.0.1",
"System.Collections": "4.0.11",
"System.ComponentModel.TypeConverter": "4.1.0",
"System.Diagnostics.Debug": "4.0.11",
"System.Dynamic.Runtime": "4.0.11",
"System.Globalization": "4.0.11",
@@ -232,6 +234,7 @@
"HAVE_TIME_SPAN_TO_STRING_WITH_CULTURE",
"HAVE_TIME_ZONE_INFO",
"HAVE_TPL",
"HAVE_TYPE_DESCRIPTOR",
"HAVE_UNICODE_SURROGATE_DETECTION",
"HAVE_VARIANT_TYPE_PARAMETERS",
"HAVE_VERSION_TRY_PARSE",
@@ -241,6 +244,7 @@
"dependencies": {
"Microsoft.CSharp": "4.0.1",
"System.Collections": "4.0.11",
"System.ComponentModel.TypeConverter": "4.1.0",
"System.Diagnostics.Debug": "4.0.11",
"System.Dynamic.Runtime": "4.0.11",
"System.Globalization": "4.0.11",