diff --git a/Src/Newtonsoft.Json/Utilities/ExpressionReflectionDelegateFactory.cs b/Src/Newtonsoft.Json/Utilities/ExpressionReflectionDelegateFactory.cs index f8fc8082..99b93846 100644 --- a/Src/Newtonsoft.Json/Utilities/ExpressionReflectionDelegateFactory.cs +++ b/Src/Newtonsoft.Json/Utilities/ExpressionReflectionDelegateFactory.cs @@ -105,18 +105,7 @@ namespace Newtonsoft.Json.Utilities Expression paramAccessorExpression = Expression.ArrayIndex(argsParameterExpression, indexExpression); - Expression argExpression; - - if (parameterType.IsValueType()) - { - BinaryExpression ensureValueTypeNotNull = Expression.Coalesce(paramAccessorExpression, Expression.New(parameterType)); - - argExpression = EnsureCastExpression(ensureValueTypeNotNull, parameterType); - } - else - { - argExpression = EnsureCastExpression(paramAccessorExpression, parameterType); - } + Expression argExpression = EnsureCastExpression(paramAccessorExpression, parameterType, !isByRef); if (isByRef) { @@ -349,26 +338,39 @@ namespace Newtonsoft.Json.Utilities Action compiled = (Action)lambdaExpression.Compile(); return compiled; } - - private Expression EnsureCastExpression(Expression expression, Type targetType) + + private Expression EnsureCastExpression(Expression expression, Type targetType, bool allowWidening = false) { Type expressionType = expression.Type; - + // check if a cast or conversion is required if (expressionType == targetType || (!expressionType.IsValueType() && targetType.IsAssignableFrom(expressionType))) { return expression; } - if (targetType.IsPrimitive()) + if (targetType.IsValueType()) { - MethodInfo toTargetTypeMethod = typeof(Convert) - .GetMethod("To" + targetType.Name, new[] { typeof(object) }); + Expression convert = Expression.Unbox(expression, targetType); - if (toTargetTypeMethod != null) + if (allowWidening && targetType.IsPrimitive()) { - expression = Expression.Call(toTargetTypeMethod, expression); + MethodInfo toTargetTypeMethod = typeof(Convert) + .GetMethod("To" + targetType.Name, new[] { typeof(object) }); + + if (toTargetTypeMethod != null) + { + convert = Expression.Condition( + Expression.TypeIs(expression, targetType), + convert, + Expression.Call(toTargetTypeMethod, expression)); + } } + + return Expression.Condition( + Expression.Equal(expression, Expression.Constant(null, typeof(object))), + Expression.Default(targetType), + convert); } return Expression.Convert(expression, targetType);