-Refactor parameterized collection creation to use delegates
This commit is contained in:
@@ -52,7 +52,6 @@ namespace Newtonsoft.Json.Tests.Linq
|
||||
[TestFixture]
|
||||
public class JValueTests : TestFixtureBase
|
||||
{
|
||||
|
||||
[Test]
|
||||
public void UndefinedTests()
|
||||
{
|
||||
|
||||
@@ -75,4 +75,4 @@ using System.Security;
|
||||
// by using the '*' as shown below:
|
||||
|
||||
[assembly: AssemblyVersion("6.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("6.0.3.17229")]
|
||||
[assembly: AssemblyFileVersion("6.0.3.17302")]
|
||||
|
||||
@@ -43,6 +43,33 @@ namespace Newtonsoft.Json.Tests.Serialization
|
||||
[TestFixture]
|
||||
public class MetadataPropertyHandlingTests : TestFixtureBase
|
||||
{
|
||||
public class User
|
||||
{
|
||||
public string Name { get; set; }
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Demo()
|
||||
{
|
||||
string json = @"{
|
||||
'Name': 'James',
|
||||
'Password': 'Password1',
|
||||
'$type': 'Newtonsoft.Json.Tests.Serialization.MetadataPropertyHandlingTests+User, Newtonsoft.Json.Tests'
|
||||
}";
|
||||
|
||||
object o = JsonConvert.DeserializeObject(json, new JsonSerializerSettings
|
||||
{
|
||||
TypeNameHandling = TypeNameHandling.All,
|
||||
// no longer needs to be first
|
||||
MetadataPropertyHandling = MetadataPropertyHandling.ReadAhead
|
||||
});
|
||||
|
||||
User u = (User)o;
|
||||
|
||||
Console.WriteLine(u.Name);
|
||||
// James
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DeserializeArraysWithPreserveObjectReferences()
|
||||
{
|
||||
|
||||
@@ -91,5 +91,5 @@ using System.Security;
|
||||
// by using the '*' as shown below:
|
||||
|
||||
[assembly: AssemblyVersion("6.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("6.0.3.17229")]
|
||||
[assembly: AssemblyFileVersion("6.0.3.17302")]
|
||||
[assembly: CLSCompliant(true)]
|
||||
|
||||
@@ -67,7 +67,7 @@ namespace Newtonsoft.Json.Serialization
|
||||
internal bool IsArray { get; private set; }
|
||||
internal bool ShouldCreateWrapper { get; private set; }
|
||||
internal bool CanDeserialize { get; private set; }
|
||||
internal MethodBase ParametrizedConstructor { get; private set; }
|
||||
internal MethodCall<object, object> ParametrizedConstructor { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="JsonArrayContract"/> class.
|
||||
@@ -198,7 +198,7 @@ namespace Newtonsoft.Json.Serialization
|
||||
|
||||
#if !(NET20 || NET35 || NET40 || PORTABLE40)
|
||||
Type immutableCreatedType;
|
||||
MethodBase immutableParameterizedCreator;
|
||||
MethodCall<object, object> immutableParameterizedCreator;
|
||||
if (ImmutableCollectionsUtils.TryBuildImmutableForArrayContract(underlyingType, CollectionItemType, out immutableCreatedType, out immutableParameterizedCreator))
|
||||
{
|
||||
CreatedType = immutableCreatedType;
|
||||
|
||||
@@ -70,7 +70,7 @@ namespace Newtonsoft.Json.Serialization
|
||||
private Func<object> _genericTemporaryDictionaryCreator;
|
||||
|
||||
internal bool ShouldCreateWrapper { get; private set; }
|
||||
internal MethodBase ParametrizedConstructor { get; private set; }
|
||||
internal MethodCall<object, object> ParametrizedCreator { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="JsonDictionaryContract"/> class.
|
||||
@@ -118,13 +118,13 @@ namespace Newtonsoft.Json.Serialization
|
||||
|
||||
if (keyType != null && valueType != null)
|
||||
{
|
||||
ParametrizedConstructor = CollectionUtils.ResolveEnumableCollectionConstructor(CreatedType, typeof(KeyValuePair<,>).MakeGenericType(keyType, valueType));
|
||||
ParametrizedCreator = CollectionUtils.ResolveEnumableCollectionConstructor(CreatedType, typeof(KeyValuePair<,>).MakeGenericType(keyType, valueType));
|
||||
|
||||
#if !(NET35 || NET20 || NETFX_CORE)
|
||||
if (ParametrizedConstructor == null && underlyingType.Name == FSharpUtils.FSharpMapTypeName)
|
||||
if (ParametrizedCreator == null && underlyingType.Name == FSharpUtils.FSharpMapTypeName)
|
||||
{
|
||||
FSharpUtils.EnsureInitialized(underlyingType.Assembly());
|
||||
ParametrizedConstructor = FSharpUtils.CreateMap(keyType, valueType);
|
||||
ParametrizedCreator = FSharpUtils.CreateMap(keyType, valueType);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -151,11 +151,11 @@ namespace Newtonsoft.Json.Serialization
|
||||
|
||||
#if !(NET20 || NET35 || NET40 || PORTABLE40)
|
||||
Type immutableCreatedType;
|
||||
MethodBase immutableParameterizedCreator;
|
||||
MethodCall<object, object> immutableParameterizedCreator;
|
||||
if (ImmutableCollectionsUtils.TryBuildImmutableForDictionaryContract(underlyingType, DictionaryKeyType, DictionaryValueType, out immutableCreatedType, out immutableParameterizedCreator))
|
||||
{
|
||||
CreatedType = immutableCreatedType;
|
||||
ParametrizedConstructor = immutableParameterizedCreator;
|
||||
ParametrizedCreator = immutableParameterizedCreator;
|
||||
IsReadOnlyOrFixedSize = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -471,11 +471,7 @@ namespace Newtonsoft.Json.Serialization
|
||||
|
||||
if (createdFromNonDefaultConstructor)
|
||||
{
|
||||
ConstructorInfo constructor = dictionaryContract.ParametrizedConstructor as ConstructorInfo;
|
||||
if (constructor != null)
|
||||
return constructor.Invoke(new object[] { dictionary });
|
||||
|
||||
return dictionaryContract.ParametrizedConstructor.Invoke(null, new object[] { dictionary });
|
||||
return dictionaryContract.ParametrizedConstructor(null , new object[] { dictionary });
|
||||
}
|
||||
else if (dictionary is IWrappedDictionary)
|
||||
{
|
||||
@@ -763,7 +759,7 @@ To fix this error either change the JSON to a {1} or change the deserialized typ
|
||||
if (contract.OnErrorCallbacks.Count > 0)
|
||||
throw JsonSerializationException.Create(reader, "Cannot call OnError on an array or readonly list, or list created from a non-default constructor: {0}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
|
||||
|
||||
if (arrayContract.ParametrizedConstructor == null && !arrayContract.IsArray)
|
||||
if (arrayContract.ParametrizedCreator == null && !arrayContract.IsArray)
|
||||
throw JsonSerializationException.Create(reader, "Cannot deserialize readonly or fixed size list: {0}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
|
||||
}
|
||||
|
||||
@@ -787,11 +783,7 @@ To fix this error either change the JSON to a {1} or change the deserialized typ
|
||||
else
|
||||
{
|
||||
// call constructor that takes IEnumerable<T>
|
||||
ConstructorInfo constructor = arrayContract.ParametrizedConstructor as ConstructorInfo;
|
||||
if (constructor != null)
|
||||
return constructor.Invoke(new object[] { list });
|
||||
|
||||
return arrayContract.ParametrizedConstructor.Invoke(null, new object[] { list });
|
||||
return arrayContract.ParametrizedCreator(null, new object[] {list});
|
||||
}
|
||||
}
|
||||
else if (list is IWrappedCollection)
|
||||
@@ -1037,7 +1029,7 @@ To fix this error either change the JSON to a {1} or change the deserialized typ
|
||||
createdFromNonDefaultConstructor = false;
|
||||
return (IList)list;
|
||||
}
|
||||
else if (contract.ParametrizedConstructor != null)
|
||||
else if (contract.ParametrizedCreator != null)
|
||||
{
|
||||
createdFromNonDefaultConstructor = true;
|
||||
return contract.CreateTemporaryCollection();
|
||||
|
||||
@@ -102,7 +102,7 @@ namespace Newtonsoft.Json.Utilities
|
||||
return false;
|
||||
}
|
||||
|
||||
public static ConstructorInfo ResolveEnumableCollectionConstructor(Type collectionType, Type collectionItemType)
|
||||
public static MethodCall<object, object> ResolveEnumableCollectionConstructor(Type collectionType, Type collectionItemType)
|
||||
{
|
||||
Type genericEnumerable = typeof(IEnumerable<>).MakeGenericType(collectionItemType);
|
||||
|
||||
@@ -113,7 +113,7 @@ namespace Newtonsoft.Json.Utilities
|
||||
if (parameters.Count == 1)
|
||||
{
|
||||
if (genericEnumerable.IsAssignableFrom(parameters[0].ParameterType))
|
||||
return constructor;
|
||||
return JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall<object>(constructor);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@ namespace Newtonsoft.Json.Utilities
|
||||
|
||||
private static bool _initialized;
|
||||
private static MethodInfo _ofSeq;
|
||||
private static Type _mapType;
|
||||
|
||||
public static Assembly FSharpCoreAssembly { get; private set; }
|
||||
public static MethodCall<object, object> IsUnion { get; private set; }
|
||||
@@ -92,6 +93,8 @@ namespace Newtonsoft.Json.Utilities
|
||||
Type listModule = fsharpCoreAssembly.GetType("Microsoft.FSharp.Collections.ListModule");
|
||||
_ofSeq = listModule.GetMethod("OfSeq");
|
||||
|
||||
_mapType = fsharpCoreAssembly.GetType("Microsoft.FSharp.Collections.FSharpMap`2");
|
||||
|
||||
#if !(NETFX_CORE || PORTABLE)
|
||||
Thread.MemoryBarrier();
|
||||
#endif
|
||||
@@ -101,55 +104,38 @@ namespace Newtonsoft.Json.Utilities
|
||||
}
|
||||
}
|
||||
|
||||
public static MethodInfo CreateSeq(Type t)
|
||||
public static MethodCall<object, object> CreateSeq(Type t)
|
||||
{
|
||||
MethodInfo seqType = _ofSeq.MakeGenericMethod(t);
|
||||
|
||||
return seqType;
|
||||
return JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall<object>(seqType);
|
||||
}
|
||||
|
||||
public static MethodInfo CreateMap(Type keyType, Type valueType)
|
||||
public static MethodCall<object, object> CreateMap(Type keyType, Type valueType)
|
||||
{
|
||||
Type t = typeof(FSharpMapCreator<,>).MakeGenericType(keyType, valueType);
|
||||
MethodInfo creatorDefinition = typeof (FSharpUtils).GetMethod("BuildMapCreator");
|
||||
|
||||
MethodInfo initializeMethod = t.GetMethod("EnsureInitialized");
|
||||
MethodInfo creatorGeneric = creatorDefinition.MakeGenericMethod(keyType, valueType);
|
||||
|
||||
initializeMethod.Invoke(null, new object[] { FSharpCoreAssembly });
|
||||
|
||||
MethodInfo typedCreateMethod = t.GetMethod("CreateMapGeneric");
|
||||
|
||||
return typedCreateMethod;
|
||||
return (MethodCall<object, object>)creatorGeneric.Invoke(null, null);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
internal static class FSharpMapCreator<TKey, TValue>
|
||||
{
|
||||
private static bool _initialized;
|
||||
private static MethodCall<object, object> _createMap;
|
||||
|
||||
public static void EnsureInitialized(Assembly fsharpCoreAssembly)
|
||||
public static MethodCall<object, object> BuildMapCreator<TKey, TValue>()
|
||||
{
|
||||
if (!_initialized)
|
||||
Type genericMapType = _mapType.MakeGenericType(typeof(TKey), typeof(TValue));
|
||||
ConstructorInfo ctor = genericMapType.GetConstructor(new[] { typeof(IEnumerable<Tuple<TKey, TValue>>) });
|
||||
MethodCall<object, object> ctorDelegate = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall<object>(ctor);
|
||||
|
||||
MethodCall<object, object> creator = (target, args) =>
|
||||
{
|
||||
Type mapType = fsharpCoreAssembly.GetType("Microsoft.FSharp.Collections.FSharpMap`2");
|
||||
// convert dictionary KeyValuePairs to Tuples
|
||||
IEnumerable<KeyValuePair<TKey, TValue>> values = (IEnumerable<KeyValuePair<TKey, TValue>>)args[0];
|
||||
IEnumerable<Tuple<TKey, TValue>> tupleValues = values.Select(kv => new Tuple<TKey, TValue>(kv.Key, kv.Value));
|
||||
|
||||
Type genericMapType = mapType.MakeGenericType(typeof(TKey), typeof(TValue));
|
||||
return ctorDelegate(null, tupleValues);
|
||||
};
|
||||
|
||||
ConstructorInfo ctor = genericMapType.GetConstructor(new[] { typeof(IEnumerable<Tuple<TKey, TValue>>) });
|
||||
|
||||
_createMap = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall<object>(ctor);
|
||||
|
||||
_initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
public static object CreateMapGeneric(IEnumerable<KeyValuePair<TKey, TValue>> values)
|
||||
{
|
||||
IEnumerable<Tuple<TKey, TValue>> tupleValues = values.Select(kv => new Tuple<TKey, TValue>(kv.Key, kv.Value));
|
||||
|
||||
object map = _createMap(null, tupleValues);
|
||||
return map;
|
||||
return creator;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
|
||||
namespace Newtonsoft.Json.Utilities
|
||||
{
|
||||
@@ -101,7 +102,7 @@ namespace Newtonsoft.Json.Utilities
|
||||
new ImmutableCollectionTypeInfo(ImmutableDictionaryGenericTypeName, ImmutableDictionaryGenericTypeName, ImmutableDictionaryTypeName)
|
||||
};
|
||||
|
||||
internal static bool TryBuildImmutableForArrayContract(Type underlyingType, Type collectionItemType, out Type createdType, out MethodBase parameterizedCreator)
|
||||
internal static bool TryBuildImmutableForArrayContract(Type underlyingType, Type collectionItemType, out Type createdType, out MethodCall<object, object> parameterizedCreator)
|
||||
{
|
||||
if (underlyingType.IsGenericType())
|
||||
{
|
||||
@@ -117,7 +118,8 @@ namespace Newtonsoft.Json.Utilities
|
||||
if (mb != null)
|
||||
{
|
||||
createdType = createdTypeDefinition.MakeGenericType(collectionItemType);
|
||||
parameterizedCreator = mb.MakeGenericMethod(collectionItemType);
|
||||
MethodInfo method = mb.MakeGenericMethod(collectionItemType);
|
||||
parameterizedCreator = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall<object>(method);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -129,7 +131,7 @@ namespace Newtonsoft.Json.Utilities
|
||||
return false;
|
||||
}
|
||||
|
||||
internal static bool TryBuildImmutableForDictionaryContract(Type underlyingType, Type keyItemType, Type valueItemType, out Type createdType, out MethodBase parameterizedCreator)
|
||||
internal static bool TryBuildImmutableForDictionaryContract(Type underlyingType, Type keyItemType, Type valueItemType, out Type createdType, out MethodCall<object, object> parameterizedCreator)
|
||||
{
|
||||
if (underlyingType.IsGenericType())
|
||||
{
|
||||
@@ -150,7 +152,8 @@ namespace Newtonsoft.Json.Utilities
|
||||
if (mb != null)
|
||||
{
|
||||
createdType = createdTypeDefinition.MakeGenericType(keyItemType, valueItemType);
|
||||
parameterizedCreator = mb.MakeGenericMethod(keyItemType, valueItemType);
|
||||
MethodInfo method = mb.MakeGenericMethod(keyItemType, valueItemType);
|
||||
parameterizedCreator = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall<object>(method);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -163,5 +166,4 @@ namespace Newtonsoft.Json.Utilities
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user