-Added support for constructors with out and ref parameters
This commit is contained in:
@@ -286,6 +286,7 @@
|
||||
<Compile Include="Utilities\DateTimeUtilsTests.cs" />
|
||||
<Compile Include="Utilities\DynamicReflectionDelegateFactoryTests.cs" />
|
||||
<Compile Include="Utilities\ExpressionReflectionDelegateFactoryTests.cs" />
|
||||
<Compile Include="Utilities\LateboundReflectionDelegateFactoryTests.cs" />
|
||||
<Compile Include="Utilities\ReflectionUtilsTests.cs" />
|
||||
<Compile Include="Utilities\StringUtilsTests.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -329,6 +329,7 @@
|
||||
<Compile Include="Utilities\DateTimeUtilsTests.cs" />
|
||||
<Compile Include="Utilities\DynamicReflectionDelegateFactoryTests.cs" />
|
||||
<Compile Include="Utilities\ExpressionReflectionDelegateFactoryTests.cs" />
|
||||
<Compile Include="Utilities\LateboundReflectionDelegateFactoryTests.cs" />
|
||||
<Compile Include="Utilities\ReflectionUtilsTests.cs" />
|
||||
<Compile Include="Utilities\StringUtilsTests.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -451,6 +451,7 @@
|
||||
<Compile Include="Utilities\DateTimeUtilsTests.cs" />
|
||||
<Compile Include="Utilities\DynamicReflectionDelegateFactoryTests.cs" />
|
||||
<Compile Include="Utilities\ExpressionReflectionDelegateFactoryTests.cs" />
|
||||
<Compile Include="Utilities\LateboundReflectionDelegateFactoryTests.cs" />
|
||||
<Compile Include="Utilities\ReflectionUtilsTests.cs" />
|
||||
<Compile Include="Utilities\StringUtilsTests.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -332,6 +332,7 @@
|
||||
<Compile Include="Utilities\ExpressionReflectionDelegateFactoryTests.cs" />
|
||||
<Compile Include="Utilities\DateTimeUtilsTests.cs" />
|
||||
<Compile Include="Utilities\DynamicReflectionDelegateFactoryTests.cs" />
|
||||
<Compile Include="Utilities\LateboundReflectionDelegateFactoryTests.cs" />
|
||||
<Compile Include="Utilities\ReflectionUtilsTests.cs" />
|
||||
<Compile Include="Utilities\StringUtilsTests.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -329,6 +329,7 @@
|
||||
<Compile Include="Utilities\DateTimeUtilsTests.cs" />
|
||||
<Compile Include="Utilities\DynamicReflectionDelegateFactoryTests.cs" />
|
||||
<Compile Include="Utilities\ExpressionReflectionDelegateFactoryTests.cs" />
|
||||
<Compile Include="Utilities\LateboundReflectionDelegateFactoryTests.cs" />
|
||||
<Compile Include="Utilities\ReflectionUtilsTests.cs" />
|
||||
<Compile Include="Utilities\StringUtilsTests.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -407,6 +407,7 @@
|
||||
<Compile Include="Utilities\DateTimeUtilsTests.cs" />
|
||||
<Compile Include="Utilities\DynamicReflectionDelegateFactoryTests.cs" />
|
||||
<Compile Include="Utilities\ExpressionReflectionDelegateFactoryTests.cs" />
|
||||
<Compile Include="Utilities\LateboundReflectionDelegateFactoryTests.cs" />
|
||||
<Compile Include="Utilities\ReflectionUtilsTests.cs" />
|
||||
<Compile Include="Utilities\StringUtilsTests.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -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")]
|
||||
|
||||
@@ -127,7 +127,7 @@ namespace Newtonsoft.Json.Tests.Serialization
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !NET20
|
||||
#if !(NET20 || NET35)
|
||||
[Test]
|
||||
public void DeserializeObservableCollection()
|
||||
{
|
||||
|
||||
@@ -48,7 +48,6 @@ using System.Collections;
|
||||
using Newtonsoft.Json.Utilities.LinqBridge;
|
||||
#else
|
||||
using System.Linq;
|
||||
|
||||
#endif
|
||||
|
||||
namespace Newtonsoft.Json.Tests
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)]
|
||||
|
||||
@@ -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
|
||||
@@ -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<ByRefParameter> refParameterMap = new List<ByRefParameter>();
|
||||
|
||||
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<ParameterExpression> variableExpressions = new List<ParameterExpression>();
|
||||
IList<Expression> bodyExpressions = new List<Expression>();
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user