diff --git a/Src/Newtonsoft.Json.Tests/JsonTextReaderTest.cs b/Src/Newtonsoft.Json.Tests/JsonTextReaderTest.cs
index 5513b257..b4150d60 100644
--- a/Src/Newtonsoft.Json.Tests/JsonTextReaderTest.cs
+++ b/Src/Newtonsoft.Json.Tests/JsonTextReaderTest.cs
@@ -26,7 +26,6 @@
using System;
using System.Collections.Generic;
using System.Globalization;
-using System.Numerics;
using System.Text;
#if !NETFX_CORE
using NUnit.Framework;
@@ -39,6 +38,9 @@ using Newtonsoft.Json;
using System.IO;
using System.Xml;
using Newtonsoft.Json.Utilities;
+#if !(NET20 || NET35 || SILVERLIGHT || PORTABLE40 || PORTABLE)
+using System.Numerics;
+#endif
namespace Newtonsoft.Json.Tests
{
diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net20.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net20.csproj
index 4c6692d6..cbee8ff8 100644
--- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net20.csproj
+++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net20.csproj
@@ -238,6 +238,7 @@
+
diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net35.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net35.csproj
index a6a73c28..16358bd4 100644
--- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net35.csproj
+++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net35.csproj
@@ -280,6 +280,7 @@
+
diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net40.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net40.csproj
index 0de0113d..3b46222d 100644
--- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net40.csproj
+++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net40.csproj
@@ -398,6 +398,7 @@
+
diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Portable.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Portable.csproj
index c9156e94..54b89ce2 100644
--- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Portable.csproj
+++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Portable.csproj
@@ -277,6 +277,7 @@
+
diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Portable40.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Portable40.csproj
index 23145fd4..53bd1940 100644
--- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Portable40.csproj
+++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Portable40.csproj
@@ -279,6 +279,7 @@
+
diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj
index 4c508c25..b6a794d0 100644
--- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj
+++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj
@@ -342,6 +342,7 @@
+
diff --git a/Src/Newtonsoft.Json.Tests/Properties/AssemblyInfo.cs b/Src/Newtonsoft.Json.Tests/Properties/AssemblyInfo.cs
index f776820d..2fa9c1a8 100644
--- a/Src/Newtonsoft.Json.Tests/Properties/AssemblyInfo.cs
+++ b/Src/Newtonsoft.Json.Tests/Properties/AssemblyInfo.cs
@@ -75,4 +75,4 @@ using System.Security;
// You can specify all the values or you can default the Revision and Build Numbers
// by using the '*' as shown below:
[assembly: AssemblyVersion("4.5.0.0")]
-[assembly: AssemblyFileVersion("5.0.4.16023")]
+[assembly: AssemblyFileVersion("5.0.4.16024")]
diff --git a/Src/Newtonsoft.Json.Tests/Utilities/ExpressionReflectionDelegateFactoryTests.cs b/Src/Newtonsoft.Json.Tests/Utilities/ExpressionReflectionDelegateFactoryTests.cs
new file mode 100644
index 00000000..c0351f73
--- /dev/null
+++ b/Src/Newtonsoft.Json.Tests/Utilities/ExpressionReflectionDelegateFactoryTests.cs
@@ -0,0 +1,302 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+#if !(PORTABLE40 || NET20 || NET35)
+using System;
+using System.Diagnostics;
+using System.Reflection;
+#if !NETFX_CORE
+using NUnit.Framework;
+#else
+using Microsoft.VisualStudio.TestPlatform.UnitTestFramework;
+using TestFixture = Microsoft.VisualStudio.TestPlatform.UnitTestFramework.TestClassAttribute;
+using Test = Microsoft.VisualStudio.TestPlatform.UnitTestFramework.TestMethodAttribute;
+#endif
+using Newtonsoft.Json.Serialization;
+using Newtonsoft.Json.Utilities;
+using Newtonsoft.Json.Tests.TestObjects;
+using Newtonsoft.Json.Tests.Serialization;
+
+namespace Newtonsoft.Json.Tests.Utilities
+{
+ [TestFixture]
+ public class ExpressionReflectionDelegateFactoryTests : TestFixtureBase
+ {
+ [Test]
+ public void DefaultConstructor()
+ {
+ Func create = ExpressionReflectionDelegateFactory.Instance.CreateDefaultConstructor(typeof(Movie));
+
+ Movie m = (Movie)create();
+ Assert.IsNotNull(m);
+ }
+
+ [Test]
+ public void DefaultConstructor_Struct()
+ {
+ Func create = ExpressionReflectionDelegateFactory.Instance.CreateDefaultConstructor(typeof(StructTest));
+
+ StructTest m = (StructTest)create();
+ Assert.IsNotNull(m);
+ }
+
+ [Test]
+ public void DefaultConstructor_Abstract()
+ {
+ ExceptionAssert.Throws("Cannot create an abstract class.",
+ () =>
+ {
+ Func create = ExpressionReflectionDelegateFactory.Instance.CreateDefaultConstructor(typeof(Type));
+
+ create();
+ });
+ }
+
+ [Test]
+ public void CreatePropertySetter()
+ {
+ Action setter = ExpressionReflectionDelegateFactory.Instance.CreateSet(typeof(Movie).GetProperty("Name"));
+
+ Movie m = new Movie();
+
+ setter(m, "OH HAI!");
+
+ Assert.AreEqual("OH HAI!", m.Name);
+ }
+
+ [Test]
+ public void CreatePropertyGetter()
+ {
+ Func getter = ExpressionReflectionDelegateFactory.Instance.CreateGet(typeof(Movie).GetProperty("Name"));
+
+ Movie m = new Movie();
+ m.Name = "OH HAI!";
+
+ object value = getter(m);
+
+ Assert.AreEqual("OH HAI!", value);
+ }
+
+ [Test]
+ public void CreateMethodCall()
+ {
+ MethodCall method = ExpressionReflectionDelegateFactory.Instance.CreateMethodCall(typeof(Movie).GetMethod("ToString"));
+
+ Movie m = new Movie();
+ object result = method(m);
+ Assert.AreEqual("Newtonsoft.Json.Tests.TestObjects.Movie", result);
+
+ method = ExpressionReflectionDelegateFactory.Instance.CreateMethodCall(typeof(Movie).GetMethod("Equals"));
+
+ result = method(m, m);
+ Assert.AreEqual(true, result);
+ }
+
+ [Test]
+ public void CreateMethodCall_Constructor()
+ {
+ MethodCall method = ExpressionReflectionDelegateFactory.Instance.CreateMethodCall(typeof(Movie).GetConstructor(new Type[0]));
+
+ object result = method(null);
+
+ Assert.IsTrue(result is Movie);
+ }
+
+ public static class StaticTestClass
+ {
+ public static string StringField;
+ public static string StringProperty { get; set; }
+ }
+
+ [Test]
+ public void GetStatic()
+ {
+ StaticTestClass.StringField = "Field!";
+ StaticTestClass.StringProperty = "Property!";
+
+ Func getter = ExpressionReflectionDelegateFactory.Instance.CreateGet(typeof(StaticTestClass).GetProperty("StringProperty"));
+
+ object v = getter(null);
+ Assert.AreEqual(StaticTestClass.StringProperty, v);
+
+ getter = ExpressionReflectionDelegateFactory.Instance.CreateGet(typeof(StaticTestClass).GetField("StringField"));
+
+ v = getter(null);
+ Assert.AreEqual(StaticTestClass.StringField, v);
+ }
+
+ [Test]
+ public void SetStatic()
+ {
+ Action setter = ExpressionReflectionDelegateFactory.Instance.CreateSet(typeof(StaticTestClass).GetProperty("StringProperty"));
+
+ setter(null, "New property!");
+ Assert.AreEqual("New property!", StaticTestClass.StringProperty);
+
+ setter = ExpressionReflectionDelegateFactory.Instance.CreateSet(typeof(StaticTestClass).GetField("StringField"));
+
+ setter(null, "New field!");
+ Assert.AreEqual("New field!", StaticTestClass.StringField);
+ }
+
+ public class FieldsTestClass
+ {
+ public string StringField;
+ public bool BoolField;
+
+ public readonly int IntReadOnlyField = int.MaxValue;
+ }
+
+ [Test]
+ public void CreateGetField()
+ {
+ FieldsTestClass c = new FieldsTestClass
+ {
+ BoolField = true,
+ StringField = "String!"
+ };
+
+ Func getter = ExpressionReflectionDelegateFactory.Instance.CreateGet(typeof(FieldsTestClass).GetField("StringField"));
+
+ object value = getter(c);
+ Assert.AreEqual("String!", value);
+
+ getter = ExpressionReflectionDelegateFactory.Instance.CreateGet(typeof(FieldsTestClass).GetField("BoolField"));
+
+ value = getter(c);
+ Assert.AreEqual(true, value);
+ }
+
+ [Test]
+ public void CreateSetField_ReadOnly()
+ {
+ FieldsTestClass c = new FieldsTestClass();
+
+ Action setter = ExpressionReflectionDelegateFactory.Instance.CreateSet(typeof(FieldsTestClass).GetField("IntReadOnlyField"));
+
+ setter(c, int.MinValue);
+ Assert.AreEqual(int.MinValue, c.IntReadOnlyField);
+ }
+
+ [Test]
+ public void CreateSetField()
+ {
+ FieldsTestClass c = new FieldsTestClass();
+
+ Action setter = ExpressionReflectionDelegateFactory.Instance.CreateSet(typeof(FieldsTestClass).GetField("StringField"));
+
+ setter(c, "String!");
+ Assert.AreEqual("String!", c.StringField);
+
+ setter = ExpressionReflectionDelegateFactory.Instance.CreateSet(typeof(FieldsTestClass).GetField("BoolField"));
+
+ setter(c, true);
+ Assert.AreEqual(true, c.BoolField);
+ }
+
+ [Test]
+ public void SetOnStruct()
+ {
+ object structTest = new StructTest();
+
+ Action setter = ExpressionReflectionDelegateFactory.Instance.CreateSet(typeof(StructTest).GetProperty("StringProperty"));
+
+ setter(structTest, "Hi1");
+ Assert.AreEqual("Hi1", ((StructTest)structTest).StringProperty);
+
+ setter = ExpressionReflectionDelegateFactory.Instance.CreateSet(typeof(StructTest).GetField("StringField"));
+
+ setter(structTest, "Hi2");
+ Assert.AreEqual("Hi2", ((StructTest)structTest).StringField);
+ }
+
+ [Test]
+ public void CreateGetWithBadObjectTarget()
+ {
+ ExceptionAssert.Throws("Unable to cast object of type 'Newtonsoft.Json.Tests.TestObjects.Person' to type 'Newtonsoft.Json.Tests.TestObjects.Movie'.",
+ () =>
+ {
+ Person p = new Person();
+ p.Name = "Hi";
+
+ Func setter = ExpressionReflectionDelegateFactory.Instance.CreateGet(typeof(Movie).GetProperty("Name"));
+
+ setter(p);
+ });
+ }
+
+ [Test]
+ public void CreateSetWithBadObjectTarget()
+ {
+ ExceptionAssert.Throws("Unable to cast object of type 'Newtonsoft.Json.Tests.TestObjects.Person' to type 'Newtonsoft.Json.Tests.TestObjects.Movie'.",
+ () =>
+ {
+ Person p = new Person();
+ Movie m = new Movie();
+
+ Action setter = ExpressionReflectionDelegateFactory.Instance.CreateSet(typeof(Movie).GetProperty("Name"));
+
+ setter(m, "Hi");
+
+ Assert.AreEqual(m.Name, "Hi");
+
+ setter(p, "Hi");
+
+ Assert.AreEqual(p.Name, "Hi");
+ });
+ }
+
+ [Test]
+ public void CreateSetWithBadObjectValue()
+ {
+ ExceptionAssert.Throws("Unable to cast object of type 'System.Version' to type 'System.String'.",
+ () =>
+ {
+ Movie m = new Movie();
+
+ Action setter = ExpressionReflectionDelegateFactory.Instance.CreateSet(typeof(Movie).GetProperty("Name"));
+
+ setter(m, new Version("1.1.1.1"));
+ });
+ }
+
+ [Test]
+ public void CreateStaticMethodCall()
+ {
+ MethodInfo castMethodInfo = typeof(JsonSerializerTest.DictionaryKey).GetMethod("op_Implicit", new[] { typeof(string) });
+
+ Assert.IsNotNull(castMethodInfo);
+
+ MethodCall call = ExpressionReflectionDelegateFactory.Instance.CreateMethodCall(castMethodInfo);
+
+ object result = call(null, "First!");
+ Assert.IsNotNull(result);
+
+ JsonSerializerTest.DictionaryKey key = (JsonSerializerTest.DictionaryKey) result;
+ Assert.AreEqual("First!", key.Value);
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.Net20.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.Net20.csproj
index 40cba141..9b25fe98 100644
--- a/Src/Newtonsoft.Json/Newtonsoft.Json.Net20.csproj
+++ b/Src/Newtonsoft.Json/Newtonsoft.Json.Net20.csproj
@@ -107,6 +107,7 @@
+
@@ -114,6 +115,10 @@
+
+
+
+
diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.Net35.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.Net35.csproj
index 9825915f..d68bcab8 100644
--- a/Src/Newtonsoft.Json/Newtonsoft.Json.Net35.csproj
+++ b/Src/Newtonsoft.Json/Newtonsoft.Json.Net35.csproj
@@ -119,6 +119,7 @@
+
@@ -226,7 +227,9 @@
+
+
diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.Net40.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.Net40.csproj
index bbab0fe9..14e005fb 100644
--- a/Src/Newtonsoft.Json/Newtonsoft.Json.Net40.csproj
+++ b/Src/Newtonsoft.Json/Newtonsoft.Json.Net40.csproj
@@ -119,6 +119,7 @@
+
@@ -225,7 +226,9 @@
+
+
diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.Portable.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.Portable.csproj
index ee32ed37..d71f7dc7 100644
--- a/Src/Newtonsoft.Json/Newtonsoft.Json.Portable.csproj
+++ b/Src/Newtonsoft.Json/Newtonsoft.Json.Portable.csproj
@@ -147,6 +147,7 @@
+
@@ -190,6 +191,7 @@
+
diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.Portable40.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.Portable40.csproj
index 00ac7103..ef3e2a85 100644
--- a/Src/Newtonsoft.Json/Newtonsoft.Json.Portable40.csproj
+++ b/Src/Newtonsoft.Json/Newtonsoft.Json.Portable40.csproj
@@ -154,6 +154,7 @@
+
@@ -201,6 +202,7 @@
+
diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.csproj
index faff3245..5eae5612 100644
--- a/Src/Newtonsoft.Json/Newtonsoft.Json.csproj
+++ b/Src/Newtonsoft.Json/Newtonsoft.Json.csproj
@@ -154,6 +154,7 @@
+
@@ -201,6 +202,7 @@
+
diff --git a/Src/Newtonsoft.Json/Properties/AssemblyInfo.cs b/Src/Newtonsoft.Json/Properties/AssemblyInfo.cs
index 668b655c..deaf24ef 100644
--- a/Src/Newtonsoft.Json/Properties/AssemblyInfo.cs
+++ b/Src/Newtonsoft.Json/Properties/AssemblyInfo.cs
@@ -92,6 +92,6 @@ using System.Security;
// You can specify all the values or you can default the Revision and Build Numbers
// by using the '*' as shown below:
[assembly: AssemblyVersion("4.5.0.0")]
-[assembly: AssemblyFileVersion("5.0.4.16023")]
+[assembly: AssemblyFileVersion("5.0.4.16024")]
[assembly: CLSCompliant(true)]
diff --git a/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs b/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs
index 9d458d07..f42ebf30 100644
--- a/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs
+++ b/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs
@@ -926,6 +926,8 @@ namespace Newtonsoft.Json.Serialization
valueProvider = new DynamicValueProvider(member);
else
valueProvider = new ReflectionValueProvider(member);
+#elif !(PORTABLE40)
+ valueProvider = new ExpressionValueProvider(member);
#else
valueProvider = new ReflectionValueProvider(member);
#endif
diff --git a/Src/Newtonsoft.Json/Serialization/ExpressionValueProvider.cs b/Src/Newtonsoft.Json/Serialization/ExpressionValueProvider.cs
new file mode 100644
index 00000000..faa3213b
--- /dev/null
+++ b/Src/Newtonsoft.Json/Serialization/ExpressionValueProvider.cs
@@ -0,0 +1,113 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+#if !(NET20 || NET35 || PORTABLE40)
+using System;
+using System.Collections.Generic;
+#if NET20
+using Newtonsoft.Json.Utilities.LinqBridge;
+#endif
+using System.Text;
+using System.Reflection;
+using Newtonsoft.Json.Utilities;
+using System.Globalization;
+
+namespace Newtonsoft.Json.Serialization
+{
+ ///
+ /// Get and set values for a using dynamic methods.
+ ///
+ public class ExpressionValueProvider : IValueProvider
+ {
+ private readonly MemberInfo _memberInfo;
+ private Func _getter;
+ private Action _setter;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The member info.
+ public ExpressionValueProvider(MemberInfo memberInfo)
+ {
+ ValidationUtils.ArgumentNotNull(memberInfo, "memberInfo");
+ _memberInfo = memberInfo;
+ }
+
+ ///
+ /// Sets the value.
+ ///
+ /// The target to set the value on.
+ /// The value to set on the target.
+ public void SetValue(object target, object value)
+ {
+ try
+ {
+ if (_setter == null)
+ _setter = ExpressionReflectionDelegateFactory.Instance.CreateSet(_memberInfo);
+
+#if DEBUG
+ // dynamic method doesn't check whether the type is 'legal' to set
+ // add this check for unit tests
+ if (value == null)
+ {
+ if (!ReflectionUtils.IsNullable(ReflectionUtils.GetMemberUnderlyingType(_memberInfo)))
+ throw new JsonSerializationException("Incompatible value. Cannot set {0} to null.".FormatWith(CultureInfo.InvariantCulture, _memberInfo));
+ }
+ else if (!ReflectionUtils.GetMemberUnderlyingType(_memberInfo).IsAssignableFrom(value.GetType()))
+ {
+ throw new JsonSerializationException("Incompatible value. Cannot set {0} to type {1}.".FormatWith(CultureInfo.InvariantCulture, _memberInfo, value.GetType()));
+ }
+#endif
+
+ _setter(target, value);
+ }
+ catch (Exception ex)
+ {
+ throw new JsonSerializationException("Error setting value to '{0}' on '{1}'.".FormatWith(CultureInfo.InvariantCulture, _memberInfo.Name, target.GetType()), ex);
+ }
+ }
+
+ ///
+ /// Gets the value.
+ ///
+ /// The target to get the value from.
+ /// The value.
+ public object GetValue(object target)
+ {
+ try
+ {
+ if (_getter == null)
+ _getter = ExpressionReflectionDelegateFactory.Instance.CreateGet(_memberInfo);
+
+ return _getter(target);
+ }
+ catch (Exception ex)
+ {
+ throw new JsonSerializationException("Error getting value from '{0}' on '{1}'.".FormatWith(CultureInfo.InvariantCulture, _memberInfo.Name, target.GetType()), ex);
+ }
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/Src/Newtonsoft.Json/Serialization/JsonTypeReflector.cs b/Src/Newtonsoft.Json/Serialization/JsonTypeReflector.cs
index baf6d657..ec55e700 100644
--- a/Src/Newtonsoft.Json/Serialization/JsonTypeReflector.cs
+++ b/Src/Newtonsoft.Json/Serialization/JsonTypeReflector.cs
@@ -436,9 +436,13 @@ namespace Newtonsoft.Json.Serialization
#if !(SILVERLIGHT || PORTABLE40 || PORTABLE || NETFX_CORE)
if (DynamicCodeGeneration)
return DynamicReflectionDelegateFactory.Instance;
-#endif
return LateBoundReflectionDelegateFactory.Instance;
+#elif !(PORTABLE40)
+ return ExpressionReflectionDelegateFactory.Instance;
+#else
+ return LateBoundReflectionDelegateFactory.Instance;
+#endif
}
}
}
diff --git a/Src/Newtonsoft.Json/Utilities/ExpressionReflectionDelegateFactory.cs b/Src/Newtonsoft.Json/Utilities/ExpressionReflectionDelegateFactory.cs
new file mode 100644
index 00000000..8416e035
--- /dev/null
+++ b/Src/Newtonsoft.Json/Utilities/ExpressionReflectionDelegateFactory.cs
@@ -0,0 +1,249 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+#if !(PORTABLE40 || NET20 || NET35)
+using System;
+using System.Linq.Expressions;
+using System.Reflection;
+
+namespace Newtonsoft.Json.Utilities
+{
+ internal class ExpressionReflectionDelegateFactory : ReflectionDelegateFactory
+ {
+ private static readonly ExpressionReflectionDelegateFactory _instance = new ExpressionReflectionDelegateFactory();
+
+ internal static ReflectionDelegateFactory Instance
+ {
+ get { return _instance; }
+ }
+
+ public override MethodCall CreateMethodCall(MethodBase method)
+ {
+ ValidationUtils.ArgumentNotNull(method, "method");
+
+ Type type = typeof(object);
+
+ ParameterExpression targetParameterExpression = Expression.Parameter(type, "target");
+ ParameterExpression argsParameterExpression = Expression.Parameter(typeof(object[]), "args");
+
+ ParameterInfo[] parametersInfo = method.GetParameters();
+
+ Expression[] argsExpression = new Expression[parametersInfo.Length];
+
+ for (int i = 0; i < parametersInfo.Length; i++)
+ {
+ Expression indexExpression = Expression.Constant(i);
+
+ Expression paramAccessorExpression = Expression.ArrayIndex(argsParameterExpression, indexExpression);
+
+ paramAccessorExpression = EnsureCastExpression(paramAccessorExpression, parametersInfo[i].ParameterType);
+
+ argsExpression[i] = paramAccessorExpression;
+ }
+
+ Expression callExpression;
+ if (method.IsConstructor)
+ {
+ callExpression = Expression.New((ConstructorInfo)method, argsExpression);
+ }
+ else if (method.IsStatic)
+ {
+ callExpression = Expression.Call((MethodInfo)method, argsExpression);
+ }
+ else
+ {
+ Expression readParameter = EnsureCastExpression(targetParameterExpression, method.DeclaringType);
+
+ callExpression = Expression.Call(readParameter, (MethodInfo)method, argsExpression);
+ }
+
+ if (method is MethodInfo)
+ callExpression = EnsureCastExpression(callExpression, type);
+
+ LambdaExpression lambdaExpression = Expression.Lambda(typeof(MethodCall), callExpression, targetParameterExpression, argsParameterExpression);
+
+ MethodCall compiled = (MethodCall)lambdaExpression.Compile();
+ return compiled;
+ }
+
+ public override Func CreateDefaultConstructor(Type type)
+ {
+ ValidationUtils.ArgumentNotNull(type, "type");
+
+ // avoid error from expressions compiler because of abstract class
+ if (type.IsAbstract())
+ return () => (T)Activator.CreateInstance(type);
+
+ Type resultType = typeof(T);
+
+ Expression expression = Expression.New(type);
+
+ expression = EnsureCastExpression(expression, resultType);
+
+ LambdaExpression lambdaExpression = Expression.Lambda(typeof(Func), expression);
+
+ Func compiled = (Func)lambdaExpression.Compile();
+ return compiled;
+ }
+
+ public override Func CreateGet(PropertyInfo propertyInfo)
+ {
+ ValidationUtils.ArgumentNotNull(propertyInfo, "propertyInfo");
+
+ Type instanceType = typeof(T);
+ Type resultType = typeof(object);
+
+ ParameterExpression parameterExpression = Expression.Parameter(instanceType, "instance");
+ Expression resultExpression;
+
+ MethodInfo getMethod = propertyInfo.GetGetMethod(true);
+
+ if (getMethod.IsStatic)
+ {
+ resultExpression = Expression.MakeMemberAccess(null, propertyInfo);
+ }
+ else
+ {
+ Expression readParameter = EnsureCastExpression(parameterExpression, propertyInfo.DeclaringType);
+
+ resultExpression = Expression.MakeMemberAccess(readParameter, propertyInfo);
+ }
+
+ resultExpression = EnsureCastExpression(resultExpression, resultType);
+
+ LambdaExpression lambdaExpression = Expression.Lambda(typeof(Func), resultExpression, parameterExpression);
+
+ Func compiled = (Func)lambdaExpression.Compile();
+ return compiled;
+ }
+
+ public override Func CreateGet(FieldInfo fieldInfo)
+ {
+ ValidationUtils.ArgumentNotNull(fieldInfo, "fieldInfo");
+
+ ParameterExpression sourceParameter = Expression.Parameter(typeof(T), "source");
+
+ Expression fieldExpression;
+ if (fieldInfo.IsStatic)
+ {
+ fieldExpression = Expression.Field(null, fieldInfo);
+ }
+ else
+ {
+ Expression sourceExpression = EnsureCastExpression(sourceParameter, fieldInfo.DeclaringType);
+
+ fieldExpression = Expression.Field(sourceExpression, fieldInfo);
+ }
+
+ fieldExpression = EnsureCastExpression(fieldExpression, typeof(object));
+
+ Func compiled = Expression.Lambda>(fieldExpression, sourceParameter).Compile();
+ return compiled;
+ }
+
+ public override Action CreateSet(FieldInfo fieldInfo)
+ {
+ ValidationUtils.ArgumentNotNull(fieldInfo, "fieldInfo");
+
+ // use reflection for structs
+ // expression doesn't correctly set value
+ if (fieldInfo.DeclaringType.IsValueType() || fieldInfo.IsInitOnly)
+ return LateBoundReflectionDelegateFactory.Instance.CreateSet(fieldInfo);
+
+ ParameterExpression sourceParameterExpression = Expression.Parameter(typeof(T), "source");
+ ParameterExpression valueParameterExpression = Expression.Parameter(typeof(object), "value");
+
+ Expression fieldExpression;
+ if (fieldInfo.IsStatic)
+ {
+ fieldExpression = Expression.Field(null, fieldInfo);
+ }
+ else
+ {
+ Expression sourceExpression = EnsureCastExpression(sourceParameterExpression, fieldInfo.DeclaringType);
+
+ fieldExpression = Expression.Field(sourceExpression, fieldInfo);
+ }
+
+ Expression valueExpression = EnsureCastExpression(valueParameterExpression, fieldExpression.Type);
+
+ BinaryExpression assignExpression = Expression.Assign(fieldExpression, valueExpression);
+
+ LambdaExpression lambdaExpression = Expression.Lambda(typeof(Action), assignExpression, sourceParameterExpression, valueParameterExpression);
+
+ Action compiled = (Action)lambdaExpression.Compile();
+ return compiled;
+ }
+
+ public override Action CreateSet(PropertyInfo propertyInfo)
+ {
+ ValidationUtils.ArgumentNotNull(propertyInfo, "propertyInfo");
+
+ // use reflection for structs
+ // expression doesn't correctly set value
+ if (propertyInfo.DeclaringType.IsValueType())
+ return LateBoundReflectionDelegateFactory.Instance.CreateSet(propertyInfo);
+
+ Type instanceType = typeof(T);
+ Type valueType = typeof(object);
+
+ ParameterExpression instanceParameter = Expression.Parameter(instanceType, "instance");
+
+ ParameterExpression valueParameter = Expression.Parameter(valueType, "value");
+ Expression readValueParameter = EnsureCastExpression(valueParameter, propertyInfo.PropertyType);
+
+ MethodInfo setMethod = propertyInfo.GetSetMethod(true);
+
+ Expression setExpression;
+ if (setMethod.IsStatic)
+ {
+ setExpression = Expression.Call(setMethod, readValueParameter);
+ }
+ else
+ {
+ Expression readInstanceParameter = EnsureCastExpression(instanceParameter, propertyInfo.DeclaringType);
+
+ setExpression = Expression.Call(readInstanceParameter, setMethod, readValueParameter);
+ }
+
+ LambdaExpression lambdaExpression = Expression.Lambda(typeof(Action), setExpression, instanceParameter, valueParameter);
+
+ Action compiled = (Action)lambdaExpression.Compile();
+ return compiled;
+ }
+
+ private Expression EnsureCastExpression(Expression expression, Type targetType)
+ {
+ Type expressionType = expression.Type;
+
+ // check if a cast or conversion is required
+ if (expressionType == targetType || (!expressionType.IsValueType() && targetType.IsAssignableFrom(expressionType)))
+ return expression;
+
+ return Expression.Convert(expression, targetType);
+ }
+ }
+}
+#endif
\ No newline at end of file