-Fixed incorrect check when looking for non-default constructors on collections

This commit is contained in:
James Newton-King
2016-04-29 18:30:38 +12:00
parent 86c2f80311
commit fe001bd5e6
4 changed files with 97 additions and 3 deletions
@@ -1917,6 +1917,86 @@ namespace Newtonsoft.Json.Tests.Serialization
Assert.AreEqual(deserializeTest2["testkey"], "");
}
#endif
[Test]
public void DeserializeCollectionWithConstructorArrayArgument()
{
var v = new ReadOnlyCollectionWithArrayArgument<double>(new[] { -0.014147478859765236, -0.011419606805541858, -0.010038461483676238 });
var json = JsonConvert.SerializeObject(v);
ExceptionAssert.Throws<JsonSerializationException>(() =>
{
JsonConvert.DeserializeObject<ReadOnlyCollectionWithArrayArgument<double>>(json);
}, "Unable to find a constructor to use for type Newtonsoft.Json.Tests.Serialization.ReadOnlyCollectionWithArrayArgument`1[System.Double]. Path '', line 1, position 1.");
}
}
public class ReadOnlyCollectionWithArrayArgument<T> : IList<T>
{
private readonly IList<T> _values;
public ReadOnlyCollectionWithArrayArgument(T[] args)
{
_values = args ?? (IList<T>)new List<T>();
}
public IEnumerator<T> GetEnumerator()
{
return _values.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return _values.GetEnumerator();
}
public void Add(T item)
{
throw new NotImplementedException();
}
public void Clear()
{
throw new NotImplementedException();
}
public bool Contains(T item)
{
throw new NotImplementedException();
}
public void CopyTo(T[] array, int arrayIndex)
{
throw new NotImplementedException();
}
public bool Remove(T item)
{
throw new NotImplementedException();
}
public int Count { get; }
public bool IsReadOnly { get; }
public int IndexOf(T item)
{
throw new NotImplementedException();
}
public void Insert(int index, T item)
{
throw new NotImplementedException();
}
public void RemoveAt(int index)
{
throw new NotImplementedException();
}
public T this[int index]
{
get { throw new NotImplementedException(); }
set { throw new NotImplementedException(); }
}
}
#if !(NET40 || NET35 || NET20 || PORTABLE40)
+2
View File
@@ -489,6 +489,8 @@ namespace Newtonsoft.Json.Linq
internal override void WriteToken(JsonReader reader, bool writeChildren, bool writeDateConstructorAsDate, bool writeComments)
{
JTokenReader tokenReader = reader as JTokenReader;
// closing the token wrather than reading then writing it doesn't lose some type information, e.g. Guid, byte[], etc
if (tokenReader != null && writeChildren && writeDateConstructorAsDate && writeComments)
{
if (tokenReader.TokenType == JsonToken.None)
@@ -172,7 +172,10 @@ namespace Newtonsoft.Json.Serialization
if (keyType != null && valueType != null)
{
_parameterizedConstructor = CollectionUtils.ResolveEnumerableCollectionConstructor(CreatedType, typeof(KeyValuePair<,>).MakeGenericType(keyType, valueType));
_parameterizedConstructor = CollectionUtils.ResolveEnumerableCollectionConstructor(
CreatedType,
typeof(KeyValuePair<,>).MakeGenericType(keyType, valueType),
typeof(IDictionary<,>).MakeGenericType(keyType, valueType));
#if !(NET35 || NET20)
if (!HasParameterizedCreatorInternal && underlyingType.Name == FSharpUtils.FSharpMapTypeName)
@@ -113,6 +113,13 @@ namespace Newtonsoft.Json.Utilities
}
public static ConstructorInfo ResolveEnumerableCollectionConstructor(Type collectionType, Type collectionItemType)
{
Type genericConstructorArgument = typeof(IList<>).MakeGenericType(collectionItemType);
return ResolveEnumerableCollectionConstructor(collectionType, collectionItemType, genericConstructorArgument);
}
public static ConstructorInfo ResolveEnumerableCollectionConstructor(Type collectionType, Type collectionItemType, Type constructorArgumentType)
{
Type genericEnumerable = typeof(IEnumerable<>).MakeGenericType(collectionItemType);
ConstructorInfo match = null;
@@ -123,7 +130,9 @@ namespace Newtonsoft.Json.Utilities
if (parameters.Count == 1)
{
if (genericEnumerable == parameters[0].ParameterType)
Type parameterType = parameters[0].ParameterType;
if (genericEnumerable == parameterType)
{
// exact match
match = constructor;
@@ -133,7 +142,7 @@ namespace Newtonsoft.Json.Utilities
// incase we can't find an exact match, use first inexact
if (match == null)
{
if (genericEnumerable.IsAssignableFrom(parameters[0].ParameterType))
if (parameterType.IsAssignableFrom(constructorArgumentType))
{
match = constructor;
}