-More object creation refactoring

This commit is contained in:
James Newton-King
2014-05-08 11:21:19 +12:00
parent a750cb9300
commit 1a6f7cdada
15 changed files with 116 additions and 87 deletions
@@ -75,4 +75,4 @@ using System.Security;
// by using the '*' as shown below:
[assembly: AssemblyVersion("6.0.0.0")]
[assembly: AssemblyFileVersion("6.0.3.17307")]
[assembly: AssemblyFileVersion("6.0.3.17308")]
@@ -91,5 +91,5 @@ using System.Security;
// by using the '*' as shown below:
[assembly: AssemblyVersion("6.0.0.0")]
[assembly: AssemblyFileVersion("6.0.3.17307")]
[assembly: AssemblyFileVersion("6.0.3.17308")]
[assembly: CLSCompliant(true)]
@@ -496,7 +496,7 @@ namespace Newtonsoft.Json.Serialization
Type enumerableWrapper = typeof(DictionaryEnumerator<,>).MakeGenericType(keyType, valueType);
ConstructorInfo constructors = enumerableWrapper.GetConstructors().First();
MethodCall<object, object> createEnumerableWrapper = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall<object>(constructors);
ObjectConstructor<object> createEnumerableWrapper = JsonTypeReflector.ReflectionDelegateFactory.CreateParametrizedConstructor(constructors);
ExtensionDataGetter extensionDataGetter = o =>
{
@@ -504,7 +504,7 @@ namespace Newtonsoft.Json.Serialization
if (dictionary == null)
return null;
return (IEnumerable<KeyValuePair<object, object>>)createEnumerableWrapper(null, dictionary);
return (IEnumerable<KeyValuePair<object, object>>)createEnumerableWrapper(dictionary);
};
if (extensionDataAttribute.ReadData)
@@ -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 MethodCall<object, object> ParametrizedCreator { get; private set; }
internal ObjectConstructor<object> ParametrizedCreator { get; private set; }
/// <summary>
/// Initializes a new instance of the <see cref="JsonArrayContract"/> class.
@@ -186,19 +186,19 @@ namespace Newtonsoft.Json.Serialization
_isCollectionItemTypeNullableType = ReflectionUtils.IsNullableType(CollectionItemType);
#if (NET20 || NET35)
// bug in .NET 2.0 & 3.5 that List<Nullable<T>> throws an error when adding null via IList.Add(object)
// wrapper will handle calling Add(T) instead
if (_isCollectionItemTypeNullableType
&& (ReflectionUtils.InheritsGenericDefinition(CreatedType, typeof(List<>), out tempCollectionType)
|| (IsArray && !IsMultidimensionalArray)))
{
ShouldCreateWrapper = true;
}
// bug in .NET 2.0 & 3.5 that List<Nullable<T>> throws an error when adding null via IList.Add(object)
// wrapper will handle calling Add(T) instead
if (_isCollectionItemTypeNullableType
&& (ReflectionUtils.InheritsGenericDefinition(CreatedType, typeof(List<>), out tempCollectionType)
|| (IsArray && !IsMultidimensionalArray)))
{
ShouldCreateWrapper = true;
}
#endif
#if !(NET20 || NET35 || NET40 || PORTABLE40)
Type immutableCreatedType;
MethodCall<object, object> immutableParameterizedCreator;
ObjectConstructor<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 MethodCall<object, object> ParametrizedCreator { get; private set; }
internal ObjectConstructor<object> ParametrizedCreator { get; private set; }
/// <summary>
/// Initializes a new instance of the <see cref="JsonDictionaryContract"/> class.
@@ -138,20 +138,20 @@ namespace Newtonsoft.Json.Serialization
_isDictionaryValueTypeNullableType = ReflectionUtils.IsNullableType(DictionaryValueType);
#if (NET20 || NET35)
Type tempDictioanryType;
Type tempDictioanryType;
// bug in .NET 2.0 & 3.5 that Dictionary<TKey, Nullable<TValue>> throws an error when adding null via IDictionary[key] = object
// wrapper will handle calling Add(T) instead
if (_isDictionaryValueTypeNullableType
&& (ReflectionUtils.InheritsGenericDefinition(CreatedType, typeof(Dictionary<,>), out tempDictioanryType)))
{
ShouldCreateWrapper = true;
}
// bug in .NET 2.0 & 3.5 that Dictionary<TKey, Nullable<TValue>> throws an error when adding null via IDictionary[key] = object
// wrapper will handle calling Add(T) instead
if (_isDictionaryValueTypeNullableType
&& (ReflectionUtils.InheritsGenericDefinition(CreatedType, typeof(Dictionary<,>), out tempDictioanryType)))
{
ShouldCreateWrapper = true;
}
#endif
#if !(NET20 || NET35 || NET40 || PORTABLE40)
Type immutableCreatedType;
MethodCall<object, object> immutableParameterizedCreator;
ObjectConstructor<object> immutableParameterizedCreator;
if (ImmutableCollectionsUtils.TryBuildImmutableForDictionaryContract(underlyingType, DictionaryKeyType, DictionaryValueType, out immutableCreatedType, out immutableParameterizedCreator))
{
CreatedType = immutableCreatedType;
@@ -84,16 +84,7 @@ namespace Newtonsoft.Json.Serialization
set
{
_overrideConstructor = value;
if (value != null)
{
MethodCall<object, object> ctor = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall<object>(value);
_overrideCreator = args => ctor(null, args);
}
else
{
_overrideCreator = null;
}
_overrideCreator = (value != null) ? JsonTypeReflector.ReflectionDelegateFactory.CreateParametrizedConstructor(value) : null;
}
}
@@ -108,24 +99,16 @@ namespace Newtonsoft.Json.Serialization
set
{
_parametrizedConstructor = value;
if (value != null)
{
MethodCall<object, object> ctor = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall<object>(value);
_parametrizedCreator = args => ctor(null, args);
}
else
{
_parametrizedCreator = null;
}
_parametrizedCreator = (value != null) ? JsonTypeReflector.ReflectionDelegateFactory.CreateParametrizedConstructor(value) : null;
}
}
/// <summary>
/// Gets or sets the function used to create the object. When set this function will override <see cref="P:DefaultCreator"/>.
/// This function can be called with a collection of arguments which are defined by the <see cref="CreatorParameters"/> collection.
/// This function is called with a collection of arguments which are defined by the <see cref="CreatorParameters"/> collection.
/// </summary>
/// <value>The function used to create the object.</value>
public Func<object[], object> OverrideCreator
public ObjectConstructor<object> OverrideCreator
{
get { return _overrideCreator; }
set
@@ -135,7 +118,7 @@ namespace Newtonsoft.Json.Serialization
}
}
internal Func<object[], object> ParametrizedCreator
internal ObjectConstructor<object> ParametrizedCreator
{
get { return _parametrizedCreator; }
}
@@ -153,8 +136,8 @@ namespace Newtonsoft.Json.Serialization
private bool? _hasRequiredOrDefaultValueProperties;
private ConstructorInfo _parametrizedConstructor;
private ConstructorInfo _overrideConstructor;
private Func<object[], object> _overrideCreator;
private Func<object[], object> _parametrizedCreator;
private ObjectConstructor<object> _overrideCreator;
private ObjectConstructor<object> _parametrizedCreator;
internal bool HasRequiredOrDefaultValueProperties
{
@@ -471,7 +471,7 @@ namespace Newtonsoft.Json.Serialization
if (createdFromNonDefaultCreator)
{
return dictionaryContract.ParametrizedCreator(null, new object[] { dictionary });
return dictionaryContract.ParametrizedCreator(dictionary);
}
else if (dictionary is IWrappedDictionary)
{
@@ -783,7 +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>
return arrayContract.ParametrizedCreator(null, new object[] {list});
return arrayContract.ParametrizedCreator(list);
}
}
else if (list is IWrappedCollection)
@@ -1568,7 +1568,7 @@ To fix this error either change the environment to be fully trusted, change the
}
#endif
private object CreateObjectUsingCreatorWithParameters(JsonReader reader, JsonObjectContract contract, JsonProperty containerProperty, Func<object[], object> creator, string id)
private object CreateObjectUsingCreatorWithParameters(JsonReader reader, JsonObjectContract contract, JsonProperty containerProperty, ObjectConstructor<object> creator, string id)
{
ValidationUtils.ArgumentNotNull(creator, "creator");
@@ -102,7 +102,7 @@ namespace Newtonsoft.Json.Utilities
return false;
}
public static MethodCall<object, object> ResolveEnumableCollectionConstructor(Type collectionType, Type collectionItemType)
public static ObjectConstructor<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 JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall<object>(constructor);
return JsonTypeReflector.ReflectionDelegateFactory.CreateParametrizedConstructor(constructor);
}
}
@@ -49,23 +49,33 @@ namespace Newtonsoft.Json.Utilities
return dynamicMethod;
}
public override ObjectConstructor<object> CreateParametrizedConstructor(MethodBase method)
{
DynamicMethod dynamicMethod = CreateDynamicMethod(method.ToString(), typeof(object), new[] { typeof(object[]) }, method.DeclaringType);
ILGenerator generator = dynamicMethod.GetILGenerator();
GenerateCreateMethodCallIL(method, generator, 0);
return (ObjectConstructor<object>)dynamicMethod.CreateDelegate(typeof(ObjectConstructor<object>));
}
public override MethodCall<T, object> CreateMethodCall<T>(MethodBase method)
{
DynamicMethod dynamicMethod = CreateDynamicMethod(method.ToString(), typeof(object), new[] { typeof(object), typeof(object[]) }, method.DeclaringType);
ILGenerator generator = dynamicMethod.GetILGenerator();
GenerateCreateMethodCallIL(method, generator);
GenerateCreateMethodCallIL(method, generator, 1);
return (MethodCall<T, object>)dynamicMethod.CreateDelegate(typeof(MethodCall<T, object>));
}
private void GenerateCreateMethodCallIL(MethodBase method, ILGenerator generator)
private void GenerateCreateMethodCallIL(MethodBase method, ILGenerator generator, int argsIndex)
{
ParameterInfo[] args = method.GetParameters();
Label argsOk = generator.DefineLabel();
generator.Emit(OpCodes.Ldarg_1);
generator.Emit(OpCodes.Ldarg, argsIndex);
generator.Emit(OpCodes.Ldlen);
generator.Emit(OpCodes.Ldc_I4, args.Length);
generator.Emit(OpCodes.Beq, argsOk);
@@ -84,7 +94,7 @@ namespace Newtonsoft.Json.Utilities
{
Type parameterType = args[i].ParameterType;
generator.Emit(OpCodes.Ldarg_1);
generator.Emit(OpCodes.Ldarg, argsIndex);
generator.Emit(OpCodes.Ldc_I4, i);
generator.Emit(OpCodes.Ldelem_Ref);
@@ -108,7 +118,7 @@ namespace Newtonsoft.Json.Utilities
// parameter has value, get value from array again and unbox
generator.MarkLabel(skipSettingDefault);
generator.Emit(OpCodes.Ldarg_1);
generator.Emit(OpCodes.Ldarg, argsIndex);
generator.Emit(OpCodes.Ldc_I4, i);
generator.Emit(OpCodes.Ldelem_Ref);
generator.UnboxIfNeeded(parameterType);
@@ -116,8 +116,8 @@ namespace Newtonsoft.Json.Utilities
Init();
return (CallSiteBinder)_getMemberCall(null, 0, name, context, _getCSharpArgumentInfoArray);
#else
return Binder.GetMember(
CSharpBinderFlags.None, name, context, new[] {CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null)});
return Binder.GetMember(
CSharpBinderFlags.None, name, context, new[] {CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null)});
#endif
}
@@ -127,12 +127,12 @@ namespace Newtonsoft.Json.Utilities
Init();
return (CallSiteBinder)_setMemberCall(null, 0, name, context, _setCSharpArgumentInfoArray);
#else
return Binder.SetMember(
CSharpBinderFlags.None, name, context, new[]
{
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType, null),
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.Constant, null)
});
return Binder.SetMember(
CSharpBinderFlags.None, name, context, new[]
{
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType, null),
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.Constant, null)
});
#endif
}
}
@@ -27,6 +27,7 @@
using System;
using System.Linq.Expressions;
using System.Reflection;
using Newtonsoft.Json.Serialization;
namespace Newtonsoft.Json.Utilities
{
@@ -39,6 +40,22 @@ namespace Newtonsoft.Json.Utilities
get { return _instance; }
}
public override ObjectConstructor<object> CreateParametrizedConstructor(MethodBase method)
{
ValidationUtils.ArgumentNotNull(method, "method");
Type type = typeof(object);
ParameterExpression argsParameterExpression = Expression.Parameter(typeof(object[]), "args");
Expression callExpression = BuildMethodCall(method, type, null, argsParameterExpression);
LambdaExpression lambdaExpression = Expression.Lambda(typeof(ObjectConstructor<object>), callExpression, argsParameterExpression);
ObjectConstructor<object> compiled = (ObjectConstructor<object>)lambdaExpression.Compile();
return compiled;
}
public override MethodCall<T, object> CreateMethodCall<T>(MethodBase method)
{
ValidationUtils.ArgumentNotNull(method, "method");
@@ -48,6 +65,16 @@ namespace Newtonsoft.Json.Utilities
ParameterExpression targetParameterExpression = Expression.Parameter(type, "target");
ParameterExpression argsParameterExpression = Expression.Parameter(typeof(object[]), "args");
Expression callExpression = BuildMethodCall(method, type, targetParameterExpression, argsParameterExpression);
LambdaExpression lambdaExpression = Expression.Lambda(typeof(MethodCall<T, object>), callExpression, targetParameterExpression, argsParameterExpression);
MethodCall<T, object> compiled = (MethodCall<T, object>)lambdaExpression.Compile();
return compiled;
}
private Expression BuildMethodCall(MethodBase method, Type type, ParameterExpression targetParameterExpression, ParameterExpression argsParameterExpression)
{
ParameterInfo[] parametersInfo = method.GetParameters();
Expression[] argsExpression = new Expression[parametersInfo.Length];
@@ -79,23 +106,23 @@ namespace Newtonsoft.Json.Utilities
Expression callExpression;
if (method.IsConstructor)
{
callExpression = Expression.New((ConstructorInfo)method, argsExpression);
callExpression = Expression.New((ConstructorInfo) method, argsExpression);
}
else if (method.IsStatic)
{
callExpression = Expression.Call((MethodInfo)method, argsExpression);
callExpression = Expression.Call((MethodInfo) method, argsExpression);
}
else
{
Expression readParameter = EnsureCastExpression(targetParameterExpression, method.DeclaringType);
callExpression = Expression.Call(readParameter, (MethodInfo)method, argsExpression);
callExpression = Expression.Call(readParameter, (MethodInfo) method, argsExpression);
}
if (method is MethodInfo)
{
MethodInfo m = (MethodInfo)method;
if (m.ReturnType != typeof(void))
MethodInfo m = (MethodInfo) method;
if (m.ReturnType != typeof (void))
callExpression = EnsureCastExpression(callExpression, type);
else
callExpression = Expression.Block(callExpression, Expression.Constant(null));
@@ -105,10 +132,7 @@ namespace Newtonsoft.Json.Utilities
callExpression = EnsureCastExpression(callExpression, type);
}
LambdaExpression lambdaExpression = Expression.Lambda(typeof(MethodCall<T, object>), callExpression, targetParameterExpression, argsParameterExpression);
MethodCall<T, object> compiled = (MethodCall<T, object>)lambdaExpression.Compile();
return compiled;
return callExpression;
}
public override Func<T> CreateDefaultConstructor<T>(Type type)
+8 -8
View File
@@ -104,35 +104,35 @@ namespace Newtonsoft.Json.Utilities
}
}
public static MethodCall<object, object> CreateSeq(Type t)
public static ObjectConstructor<object> CreateSeq(Type t)
{
MethodInfo seqType = _ofSeq.MakeGenericMethod(t);
return JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall<object>(seqType);
return JsonTypeReflector.ReflectionDelegateFactory.CreateParametrizedConstructor(seqType);
}
public static MethodCall<object, object> CreateMap(Type keyType, Type valueType)
public static ObjectConstructor<object> CreateMap(Type keyType, Type valueType)
{
MethodInfo creatorDefinition = typeof (FSharpUtils).GetMethod("BuildMapCreator");
MethodInfo creatorGeneric = creatorDefinition.MakeGenericMethod(keyType, valueType);
return (MethodCall<object, object>)creatorGeneric.Invoke(null, null);
return (ObjectConstructor<object>)creatorGeneric.Invoke(null, null);
}
public static MethodCall<object, object> BuildMapCreator<TKey, TValue>()
public static ObjectConstructor<object> BuildMapCreator<TKey, TValue>()
{
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);
ObjectConstructor<object> ctorDelegate = JsonTypeReflector.ReflectionDelegateFactory.CreateParametrizedConstructor(ctor);
MethodCall<object, object> creator = (target, args) =>
ObjectConstructor<object> creator = args =>
{
// 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));
return ctorDelegate(null, tupleValues);
return ctorDelegate(tupleValues);
};
return creator;
@@ -102,7 +102,7 @@ namespace Newtonsoft.Json.Utilities
new ImmutableCollectionTypeInfo(ImmutableDictionaryGenericTypeName, ImmutableDictionaryGenericTypeName, ImmutableDictionaryTypeName)
};
internal static bool TryBuildImmutableForArrayContract(Type underlyingType, Type collectionItemType, out Type createdType, out MethodCall<object, object> parameterizedCreator)
internal static bool TryBuildImmutableForArrayContract(Type underlyingType, Type collectionItemType, out Type createdType, out ObjectConstructor<object> parameterizedCreator)
{
if (underlyingType.IsGenericType())
{
@@ -119,7 +119,7 @@ namespace Newtonsoft.Json.Utilities
{
createdType = createdTypeDefinition.MakeGenericType(collectionItemType);
MethodInfo method = mb.MakeGenericMethod(collectionItemType);
parameterizedCreator = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall<object>(method);
parameterizedCreator = JsonTypeReflector.ReflectionDelegateFactory.CreateParametrizedConstructor(method);
return true;
}
}
@@ -131,7 +131,7 @@ namespace Newtonsoft.Json.Utilities
return false;
}
internal static bool TryBuildImmutableForDictionaryContract(Type underlyingType, Type keyItemType, Type valueItemType, out Type createdType, out MethodCall<object, object> parameterizedCreator)
internal static bool TryBuildImmutableForDictionaryContract(Type underlyingType, Type keyItemType, Type valueItemType, out Type createdType, out ObjectConstructor<object> parameterizedCreator)
{
if (underlyingType.IsGenericType())
{
@@ -153,7 +153,7 @@ namespace Newtonsoft.Json.Utilities
{
createdType = createdTypeDefinition.MakeGenericType(keyItemType, valueItemType);
MethodInfo method = mb.MakeGenericMethod(keyItemType, valueItemType);
parameterizedCreator = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall<object>(method);
parameterizedCreator = JsonTypeReflector.ReflectionDelegateFactory.CreateParametrizedConstructor(method);
return true;
}
}
@@ -42,6 +42,17 @@ namespace Newtonsoft.Json.Utilities
get { return _instance; }
}
public override ObjectConstructor<object> CreateParametrizedConstructor(MethodBase method)
{
ValidationUtils.ArgumentNotNull(method, "method");
ConstructorInfo c = method as ConstructorInfo;
if (c != null)
return c.Invoke;
return a => method.Invoke(null, a);
}
public override MethodCall<T, object> CreateMethodCall<T>(MethodBase method)
{
ValidationUtils.ArgumentNotNull(method, "method");
@@ -63,6 +63,7 @@ namespace Newtonsoft.Json.Utilities
}
public abstract MethodCall<T, object> CreateMethodCall<T>(MethodBase method);
public abstract ObjectConstructor<object> CreateParametrizedConstructor(MethodBase method);
public abstract Func<T> CreateDefaultConstructor<T>(Type type);
public abstract Func<T, object> CreateGet<T>(PropertyInfo propertyInfo);
public abstract Func<T, object> CreateGet<T>(FieldInfo fieldInfo);