diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net20.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net20.csproj
index d6c44749..97a08bb7 100644
--- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net20.csproj
+++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net20.csproj
@@ -286,6 +286,7 @@
+
diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net35.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net35.csproj
index ba48e820..22f1b1f5 100644
--- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net35.csproj
+++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net35.csproj
@@ -329,6 +329,7 @@
+
diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net40.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net40.csproj
index 356e47d8..92d46d05 100644
--- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net40.csproj
+++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net40.csproj
@@ -451,6 +451,7 @@
+
diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Portable.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Portable.csproj
index e06c8aa4..4dbae464 100644
--- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Portable.csproj
+++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Portable.csproj
@@ -332,6 +332,7 @@
+
diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Portable40.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Portable40.csproj
index b0b00751..57302c64 100644
--- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Portable40.csproj
+++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Portable40.csproj
@@ -329,6 +329,7 @@
+
diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj
index b2b696df..773e0b6a 100644
--- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj
+++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj
@@ -407,6 +407,7 @@
+
diff --git a/Src/Newtonsoft.Json.Tests/Properties/AssemblyInfo.cs b/Src/Newtonsoft.Json.Tests/Properties/AssemblyInfo.cs
index b2213523..aed2b78f 100644
--- a/Src/Newtonsoft.Json.Tests/Properties/AssemblyInfo.cs
+++ b/Src/Newtonsoft.Json.Tests/Properties/AssemblyInfo.cs
@@ -75,4 +75,4 @@ using System.Security;
// by using the '*' as shown below:
[assembly: AssemblyVersion("6.0.0.0")]
-[assembly: AssemblyFileVersion("6.0.4.17624")]
+[assembly: AssemblyFileVersion("6.0.4.17631")]
diff --git a/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs b/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs
index 35d72cf7..92d02a0a 100644
--- a/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs
+++ b/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs
@@ -127,7 +127,7 @@ namespace Newtonsoft.Json.Tests.Serialization
}
#endif
-#if !NET20
+#if !(NET20 || NET35)
[Test]
public void DeserializeObservableCollection()
{
diff --git a/Src/Newtonsoft.Json.Tests/TestFixtureBase.cs b/Src/Newtonsoft.Json.Tests/TestFixtureBase.cs
index 3ff2597f..15044ce6 100644
--- a/Src/Newtonsoft.Json.Tests/TestFixtureBase.cs
+++ b/Src/Newtonsoft.Json.Tests/TestFixtureBase.cs
@@ -48,7 +48,6 @@ using System.Collections;
using Newtonsoft.Json.Utilities.LinqBridge;
#else
using System.Linq;
-
#endif
namespace Newtonsoft.Json.Tests
diff --git a/Src/Newtonsoft.Json.Tests/Utilities/DynamicReflectionDelegateFactoryTests.cs b/Src/Newtonsoft.Json.Tests/Utilities/DynamicReflectionDelegateFactoryTests.cs
index 9eea3acf..13ac99f7 100644
--- a/Src/Newtonsoft.Json.Tests/Utilities/DynamicReflectionDelegateFactoryTests.cs
+++ b/Src/Newtonsoft.Json.Tests/Utilities/DynamicReflectionDelegateFactoryTests.cs
@@ -38,12 +38,59 @@ using Newtonsoft.Json.Serialization;
using Newtonsoft.Json.Utilities;
using Newtonsoft.Json.Tests.TestObjects;
using Newtonsoft.Json.Tests.Serialization;
+#if NET20
+using Newtonsoft.Json.Utilities.LinqBridge;
+#else
+using System.Linq;
+#endif
namespace Newtonsoft.Json.Tests.Utilities
{
[TestFixture]
public class DynamicReflectionDelegateFactoryTests : TestFixtureBase
{
+ [Test]
+ public void ConstructorWithRefString()
+ {
+ ConstructorInfo constructor = typeof(OutAndRefTestClass).GetConstructors().Single(c => c.GetParameters().Count() == 1);
+
+ var creator = DynamicReflectionDelegateFactory.Instance.CreateParametrizedConstructor(constructor);
+
+ object[] args = new object[] { "Input" };
+ OutAndRefTestClass o = (OutAndRefTestClass)creator(args);
+ Assert.IsNotNull(o);
+ Assert.AreEqual("Input", o.Input);
+ }
+
+ [Test]
+ public void ConstructorWithRefStringAndOutBool()
+ {
+ ConstructorInfo constructor = typeof(OutAndRefTestClass).GetConstructors().Single(c => c.GetParameters().Count() == 2);
+
+ var creator = DynamicReflectionDelegateFactory.Instance.CreateParametrizedConstructor(constructor);
+
+ object[] args = new object[] { "Input", false };
+ OutAndRefTestClass o = (OutAndRefTestClass)creator(args);
+ Assert.IsNotNull(o);
+ Assert.AreEqual("Input", o.Input);
+ Assert.AreEqual(true, o.B1);
+ }
+
+ [Test]
+ public void ConstructorWithRefStringAndRefBoolAndRefBool()
+ {
+ ConstructorInfo constructor = typeof(OutAndRefTestClass).GetConstructors().Single(c => c.GetParameters().Count() == 3);
+
+ var creator = DynamicReflectionDelegateFactory.Instance.CreateParametrizedConstructor(constructor);
+
+ object[] args = new object[] { "Input", true, null };
+ OutAndRefTestClass o = (OutAndRefTestClass)creator(args);
+ Assert.IsNotNull(o);
+ Assert.AreEqual("Input", o.Input);
+ Assert.AreEqual(true, o.B1);
+ Assert.AreEqual(false, o.B2);
+ }
+
[Test]
public void CreateGetWithBadObjectTarget()
{
diff --git a/Src/Newtonsoft.Json.Tests/Utilities/ExpressionReflectionDelegateFactoryTests.cs b/Src/Newtonsoft.Json.Tests/Utilities/ExpressionReflectionDelegateFactoryTests.cs
index 6129509b..7db83186 100644
--- a/Src/Newtonsoft.Json.Tests/Utilities/ExpressionReflectionDelegateFactoryTests.cs
+++ b/Src/Newtonsoft.Json.Tests/Utilities/ExpressionReflectionDelegateFactoryTests.cs
@@ -24,6 +24,7 @@
#endregion
#if !(NET20 || NET35)
+using System.Linq;
using System;
using System.Diagnostics;
using System.Reflection;
@@ -44,6 +45,47 @@ namespace Newtonsoft.Json.Tests.Utilities
[TestFixture]
public class ExpressionReflectionDelegateFactoryTests : TestFixtureBase
{
+ [Test]
+ public void ConstructorWithRefString()
+ {
+ ConstructorInfo constructor = typeof(OutAndRefTestClass).GetConstructors().Single(c => c.GetParameters().Count() == 1);
+
+ var creator = ExpressionReflectionDelegateFactory.Instance.CreateParametrizedConstructor(constructor);
+
+ object[] args = new object[] { "Input" };
+ OutAndRefTestClass o = (OutAndRefTestClass)creator(args);
+ Assert.IsNotNull(o);
+ Assert.AreEqual("Input", o.Input);
+ }
+
+ [Test]
+ public void ConstructorWithRefStringAndOutBool()
+ {
+ ConstructorInfo constructor = typeof(OutAndRefTestClass).GetConstructors().Single(c => c.GetParameters().Count() == 2);
+
+ var creator = ExpressionReflectionDelegateFactory.Instance.CreateParametrizedConstructor(constructor);
+
+ object[] args = new object[] { "Input", null };
+ OutAndRefTestClass o = (OutAndRefTestClass)creator(args);
+ Assert.IsNotNull(o);
+ Assert.AreEqual("Input", o.Input);
+ }
+
+ [Test]
+ public void ConstructorWithRefStringAndRefBoolAndRefBool()
+ {
+ ConstructorInfo constructor = typeof(OutAndRefTestClass).GetConstructors().Single(c => c.GetParameters().Count() == 3);
+
+ var creator = ExpressionReflectionDelegateFactory.Instance.CreateParametrizedConstructor(constructor);
+
+ object[] args = new object[] { "Input", true, null };
+ OutAndRefTestClass o = (OutAndRefTestClass)creator(args);
+ Assert.IsNotNull(o);
+ Assert.AreEqual("Input", o.Input);
+ Assert.AreEqual(true, o.B1);
+ Assert.AreEqual(false, o.B2);
+ }
+
[Test]
public void DefaultConstructor()
{
diff --git a/Src/Newtonsoft.Json.Tests/Utilities/LateboundReflectionDelegateFactoryTests.cs b/Src/Newtonsoft.Json.Tests/Utilities/LateboundReflectionDelegateFactoryTests.cs
new file mode 100644
index 00000000..ef61adc0
--- /dev/null
+++ b/Src/Newtonsoft.Json.Tests/Utilities/LateboundReflectionDelegateFactoryTests.cs
@@ -0,0 +1,83 @@
+using System.Reflection;
+using Newtonsoft.Json.Utilities;
+using NUnit.Framework;
+#if NET20
+using Newtonsoft.Json.Utilities.LinqBridge;
+#else
+using System.Linq;
+#endif
+
+namespace Newtonsoft.Json.Tests.Utilities
+{
+ public class OutAndRefTestClass
+ {
+ public string Input { get; set; }
+ public bool B1 { get; set; }
+ public bool B2 { get; set; }
+
+ public OutAndRefTestClass(ref string value)
+ {
+ Input = value;
+ value = "Output";
+ }
+
+ public OutAndRefTestClass(ref string value, out bool b1)
+ : this(ref value)
+ {
+ b1 = true;
+ B1 = true;
+ }
+
+ public OutAndRefTestClass(ref string value, ref bool b1, ref bool b2)
+ : this(ref value)
+ {
+ B1 = b1;
+ B2 = b2;
+ }
+ }
+
+ [TestFixture]
+ public class LateboundReflectionDelegateFactoryTests : TestFixtureBase
+ {
+ [Test]
+ public void ConstructorWithRefString()
+ {
+ ConstructorInfo constructor = typeof(OutAndRefTestClass).GetConstructors().Single(c => c.GetParameters().Count() == 1);
+
+ var creator = LateBoundReflectionDelegateFactory.Instance.CreateParametrizedConstructor(constructor);
+
+ object[] args = new object[] { "Input" };
+ OutAndRefTestClass o = (OutAndRefTestClass)creator(args);
+ Assert.IsNotNull(o);
+ Assert.AreEqual("Input", o.Input);
+ }
+
+ [Test]
+ public void ConstructorWithRefStringAndOutBool()
+ {
+ ConstructorInfo constructor = typeof(OutAndRefTestClass).GetConstructors().Single(c => c.GetParameters().Count() == 2);
+
+ var creator = LateBoundReflectionDelegateFactory.Instance.CreateParametrizedConstructor(constructor);
+
+ object[] args = new object[] { "Input", null };
+ OutAndRefTestClass o = (OutAndRefTestClass)creator(args);
+ Assert.IsNotNull(o);
+ Assert.AreEqual("Input", o.Input);
+ }
+
+ [Test]
+ public void ConstructorWithRefStringAndRefBoolAndRefBool()
+ {
+ ConstructorInfo constructor = typeof(OutAndRefTestClass).GetConstructors().Single(c => c.GetParameters().Count() == 3);
+
+ var creator = LateBoundReflectionDelegateFactory.Instance.CreateParametrizedConstructor(constructor);
+
+ object[] args = new object[] { "Input", true, null };
+ OutAndRefTestClass o = (OutAndRefTestClass)creator(args);
+ Assert.IsNotNull(o);
+ Assert.AreEqual("Input", o.Input);
+ Assert.AreEqual(true, o.B1);
+ Assert.AreEqual(false, o.B2);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Src/Newtonsoft.Json/Properties/AssemblyInfo.cs b/Src/Newtonsoft.Json/Properties/AssemblyInfo.cs
index 52fe5f60..b90d57ef 100644
--- a/Src/Newtonsoft.Json/Properties/AssemblyInfo.cs
+++ b/Src/Newtonsoft.Json/Properties/AssemblyInfo.cs
@@ -91,5 +91,5 @@ using System.Security;
// by using the '*' as shown below:
[assembly: AssemblyVersion("6.0.0.0")]
-[assembly: AssemblyFileVersion("6.0.4.17624")]
+[assembly: AssemblyFileVersion("6.0.4.17631")]
[assembly: CLSCompliant(true)]
diff --git a/Src/Newtonsoft.Json/Utilities/DynamicReflectionDelegateFactory.cs b/Src/Newtonsoft.Json/Utilities/DynamicReflectionDelegateFactory.cs
index fc5cd25c..4c251e81 100644
--- a/Src/Newtonsoft.Json/Utilities/DynamicReflectionDelegateFactory.cs
+++ b/Src/Newtonsoft.Json/Utilities/DynamicReflectionDelegateFactory.cs
@@ -92,15 +92,63 @@ namespace Newtonsoft.Json.Utilities
for (int i = 0; i < args.Length; i++)
{
- Type parameterType = args[i].ParameterType;
+ ParameterInfo parameter = args[i];
+ Type parameterType = parameter.ParameterType;
- generator.Emit(OpCodes.Ldarg, argsIndex);
-
- generator.Emit(OpCodes.Ldc_I4, i);
- generator.Emit(OpCodes.Ldelem_Ref);
-
- if (parameterType.IsValueType())
+ if (parameterType.IsByRef)
{
+ parameterType = parameterType.GetElementType();
+
+ LocalBuilder localVariable = generator.DeclareLocal(parameterType);
+
+ // don't need to set variable for 'out' parameter
+ if (!parameter.IsOut)
+ {
+ generator.Emit(OpCodes.Ldarg, argsIndex);
+ generator.Emit(OpCodes.Ldc_I4, i);
+ generator.Emit(OpCodes.Ldelem_Ref);
+
+ if (parameterType.IsValueType())
+ {
+ Label skipSettingDefault = generator.DefineLabel();
+ Label finishedProcessingParameter = generator.DefineLabel();
+
+ // check if parameter is not null
+ generator.Emit(OpCodes.Brtrue_S, skipSettingDefault);
+
+ // parameter has no value, initialize to default
+ generator.Emit(OpCodes.Ldloca_S, localVariable);
+ generator.Emit(OpCodes.Initobj, parameterType);
+ generator.Emit(OpCodes.Br_S, finishedProcessingParameter);
+
+ // parameter has value, get value from array again and unbox and set to variable
+ generator.MarkLabel(skipSettingDefault);
+ generator.Emit(OpCodes.Ldarg, argsIndex);
+ generator.Emit(OpCodes.Ldc_I4, i);
+ generator.Emit(OpCodes.Ldelem_Ref);
+ generator.UnboxIfNeeded(parameterType);
+ generator.Emit(OpCodes.Stloc, localVariableCount);
+
+ // parameter finished, we out!
+ generator.MarkLabel(finishedProcessingParameter);
+ }
+ else
+ {
+ generator.UnboxIfNeeded(parameterType);
+ generator.Emit(OpCodes.Stloc, localVariableCount);
+ }
+ }
+
+ generator.Emit(OpCodes.Ldloca_S, localVariable);
+
+ localVariableCount++;
+ }
+ else if (parameterType.IsValueType())
+ {
+ generator.Emit(OpCodes.Ldarg, argsIndex);
+ generator.Emit(OpCodes.Ldc_I4, i);
+ generator.Emit(OpCodes.Ldelem_Ref);
+
// have to check that value type parameters aren't null
// otherwise they will error when unboxed
Label skipSettingDefault = generator.DefineLabel();
@@ -127,8 +175,12 @@ namespace Newtonsoft.Json.Utilities
generator.MarkLabel(finishedProcessingParameter);
localVariableCount++;
}
- else
+ else
{
+ generator.Emit(OpCodes.Ldarg, argsIndex);
+ generator.Emit(OpCodes.Ldc_I4, i);
+ generator.Emit(OpCodes.Ldelem_Ref);
+
generator.UnboxIfNeeded(parameterType);
}
}
@@ -283,5 +335,4 @@ namespace Newtonsoft.Json.Utilities
}
}
}
-
#endif
\ No newline at end of file
diff --git a/Src/Newtonsoft.Json/Utilities/ExpressionReflectionDelegateFactory.cs b/Src/Newtonsoft.Json/Utilities/ExpressionReflectionDelegateFactory.cs
index d6f2dbbf..6cb95a37 100644
--- a/Src/Newtonsoft.Json/Utilities/ExpressionReflectionDelegateFactory.cs
+++ b/Src/Newtonsoft.Json/Utilities/ExpressionReflectionDelegateFactory.cs
@@ -24,6 +24,9 @@
#endregion
#if !(NET20 || NET35)
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
using System;
using System.Linq.Expressions;
using System.Reflection;
@@ -73,15 +76,30 @@ namespace Newtonsoft.Json.Utilities
return compiled;
}
+ private class ByRefParameter
+ {
+ public Expression Value;
+ public ParameterExpression Variable;
+ public bool IsOut;
+ }
+
private Expression BuildMethodCall(MethodBase method, Type type, ParameterExpression targetParameterExpression, ParameterExpression argsParameterExpression)
{
ParameterInfo[] parametersInfo = method.GetParameters();
Expression[] argsExpression = new Expression[parametersInfo.Length];
+ IList refParameterMap = new List();
for (int i = 0; i < parametersInfo.Length; i++)
{
- Type parameterType = parametersInfo[i].ParameterType;
+ ParameterInfo parameter = parametersInfo[i];
+ Type parameterType = parameter.ParameterType;
+ bool isByRef = false;
+ if (parameterType.IsByRef)
+ {
+ parameterType = parameterType.GetElementType();
+ isByRef = true;
+ }
Expression indexExpression = Expression.Constant(i);
@@ -100,6 +118,19 @@ namespace Newtonsoft.Json.Utilities
argExpression = EnsureCastExpression(paramAccessorExpression, parameterType);
}
+ if (isByRef)
+ {
+ ParameterExpression variable = Expression.Variable(parameterType);
+ refParameterMap.Add(new ByRefParameter
+ {
+ Value = argExpression,
+ Variable = variable,
+ IsOut = parameter.IsOut
+ });
+
+ argExpression = variable;
+ }
+
argsExpression[i] = argExpression;
}
@@ -132,6 +163,23 @@ namespace Newtonsoft.Json.Utilities
callExpression = EnsureCastExpression(callExpression, type);
}
+ if (refParameterMap.Count > 0)
+ {
+ IList variableExpressions = new List();
+ IList bodyExpressions = new List();
+ foreach (ByRefParameter p in refParameterMap)
+ {
+ if (!p.IsOut)
+ bodyExpressions.Add(Expression.Assign(p.Variable, p.Value));
+
+ variableExpressions.Add(p.Variable);
+ }
+
+ bodyExpressions.Add(callExpression);
+
+ callExpression = Expression.Block(variableExpressions, bodyExpressions);
+ }
+
return callExpression;
}