Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/Newtonsoft.Json.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJamesNK <james@newtonking.com>2010-11-25 10:11:38 +0300
committerJamesNK <james@newtonking.com>2010-11-25 10:11:38 +0300
commitefc2310a3dbcfbd6820dd57ad62ffa473258f5bc (patch)
tree0d62a86f0c9196dc035c961946ddccf84f756324
parent5c0431464be353671d2c3b9607018fbf34045657 (diff)
-Make .NET 4.0 dynamic actually work (oops)
-Added JValue dynamic value conversion
-rw-r--r--Src/Newtonsoft.Json.Tests/Linq/DynamicTests.cs20
-rw-r--r--Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net35.csproj1
-rw-r--r--Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs58
-rw-r--r--Src/Newtonsoft.Json.Tests/Serialization/TypeNameHandlingTests.cs63
-rw-r--r--Src/Newtonsoft.Json/JsonReader.cs4
-rw-r--r--Src/Newtonsoft.Json/Linq/JObject.cs18
-rw-r--r--Src/Newtonsoft.Json/Linq/JToken.cs2
-rw-r--r--Src/Newtonsoft.Json/Linq/JValue.cs55
-rw-r--r--Src/Newtonsoft.Json/Utilities/DynamicProxy.cs33
-rw-r--r--Src/Newtonsoft.Json/Utilities/DynamicProxyMetaObject.cs42
10 files changed, 179 insertions, 117 deletions
diff --git a/Src/Newtonsoft.Json.Tests/Linq/DynamicTests.cs b/Src/Newtonsoft.Json.Tests/Linq/DynamicTests.cs
index 3ff59ab..e592243 100644
--- a/Src/Newtonsoft.Json.Tests/Linq/DynamicTests.cs
+++ b/Src/Newtonsoft.Json.Tests/Linq/DynamicTests.cs
@@ -119,6 +119,18 @@ namespace Newtonsoft.Json.Tests.Linq
Assert.AreEqual(2, memberNames.Count);
Assert.AreEqual("ChildValue", memberNames[0]);
Assert.AreEqual("Hello Joe", memberNames[1]);
+
+ o = new JObject(
+ new JProperty("ChildValue1", "blah blah"),
+ new JProperty("Hello Joe1", null));
+
+ d = o;
+
+ memberNames = o.GetDynamicMemberNames().ToList();
+
+ Assert.AreEqual(2, memberNames.Count);
+ Assert.AreEqual("ChildValue1", memberNames[0]);
+ Assert.AreEqual("Hello Joe1", memberNames[1]);
}
[Test]
@@ -126,11 +138,15 @@ namespace Newtonsoft.Json.Tests.Linq
{
AssertValueConverted<bool>(true);
AssertValueConverted<bool?>(true);
+ AssertValueConverted<bool?>(false);
+ AssertValueConverted<byte[]>(null);
AssertValueConverted<byte[]>(Encoding.UTF8.GetBytes("blah"));
AssertValueConverted<DateTime>(new DateTime(2000, 12, 20, 23, 59, 2, DateTimeKind.Utc));
AssertValueConverted<DateTime?>(new DateTime(2000, 12, 20, 23, 59, 2, DateTimeKind.Utc));
+ AssertValueConverted<DateTime?>(null);
AssertValueConverted<DateTimeOffset>(new DateTimeOffset(2000, 12, 20, 23, 59, 2, TimeSpan.FromHours(1)));
AssertValueConverted<DateTimeOffset?>(new DateTimeOffset(2000, 12, 20, 23, 59, 2, TimeSpan.FromHours(1)));
+ AssertValueConverted<DateTimeOffset?>(null);
AssertValueConverted<decimal>(99.9m);
AssertValueConverted<decimal?>(99.9m);
AssertValueConverted<double>(99.9);
@@ -150,6 +166,7 @@ namespace Newtonsoft.Json.Tests.Linq
AssertValueConverted<ulong?>(ulong.MaxValue);
AssertValueConverted<ushort>(ushort.MinValue);
AssertValueConverted<ushort?>(ushort.MinValue);
+ AssertValueConverted<ushort?>(null);
}
private static void AssertValueConverted<T>(T value)
@@ -157,7 +174,8 @@ namespace Newtonsoft.Json.Tests.Linq
JValue v = new JValue(value);
dynamic d = v;
- Assert.AreEqual(value, (T)d);
+ T t = d;
+ Assert.AreEqual(value, t);
}
}
}
diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net35.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net35.csproj
index 0ec68d9..fd3f41f 100644
--- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net35.csproj
+++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net35.csproj
@@ -267,7 +267,6 @@
<Compile Include="Utilities\ReflectionUtilsTests.cs" />
</ItemGroup>
<ItemGroup>
- <None Include="App.Config" />
<None Include="LinqToSql\LinqToSqlClasses.dbml">
<Generator>MSLinqToSQLGenerator</Generator>
<LastGenOutput>LinqToSqlClasses.designer.cs</LastGenOutput>
diff --git a/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs b/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs
index cc80491..82b5f58 100644
--- a/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs
+++ b/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs
@@ -3827,63 +3827,5 @@ keyword such as type of business.""
});
}
#endif
-
- [Test]
- public void SerializingIEnumerableOfTShouldRetainGenericTypeInfo()
- {
- CustomEnumerable<Product> products = new CustomEnumerable<Product>();
-
- string json = JsonConvert.SerializeObject(products, Formatting.Indented, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All });
-
- Assert.AreEqual(@"{
- ""$type"": ""Newtonsoft.Json.Tests.TestObjects.Product[], Newtonsoft.Json.Tests"",
- ""$values"": []
-}", json);
- }
-
- public class CustomEnumerable<T> : IEnumerable<T>
- {
- //NOTE: a simple linked list
- private readonly T value;
- private readonly CustomEnumerable<T> next;
- private readonly int count;
-
- private CustomEnumerable(T value, CustomEnumerable<T> next)
- {
- this.value = value;
- this.next = next;
- count = this.next.count + 1;
- }
-
- public CustomEnumerable()
- {
- count = 0;
- }
-
- public CustomEnumerable<T> AddFirst(T newVal)
- {
- return new CustomEnumerable<T>(newVal, this);
- }
-
- public IEnumerator<T> GetEnumerator()
- {
- if (count == 0) // last node
- yield break;
- yield return value;
-
- var nextInLine = next;
- while (nextInLine != null)
- {
- if (nextInLine.count != 0)
- yield return nextInLine.value;
- nextInLine = nextInLine.next;
- }
- }
-
- IEnumerator IEnumerable.GetEnumerator()
- {
- return GetEnumerator();
- }
- }
}
} \ No newline at end of file
diff --git a/Src/Newtonsoft.Json.Tests/Serialization/TypeNameHandlingTests.cs b/Src/Newtonsoft.Json.Tests/Serialization/TypeNameHandlingTests.cs
index 9344d76..715b939 100644
--- a/Src/Newtonsoft.Json.Tests/Serialization/TypeNameHandlingTests.cs
+++ b/Src/Newtonsoft.Json.Tests/Serialization/TypeNameHandlingTests.cs
@@ -24,6 +24,7 @@
#endregion
using System;
+using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization.Formatters;
@@ -640,6 +641,68 @@ namespace Newtonsoft.Json.Tests.Serialization
List<UrlStatus> statues = (List<UrlStatus>) newCollection["List"];
Assert.AreEqual(2, statues.Count);
}
+
+
+ [Test]
+ public void SerializingIEnumerableOfTShouldRetainGenericTypeInfo()
+ {
+ string productClassRef = ReflectionUtils.GetTypeName(typeof(Product[]), FormatterAssemblyStyle.Simple);
+
+ CustomEnumerable<Product> products = new CustomEnumerable<Product>();
+
+ string json = JsonConvert.SerializeObject(products, Formatting.Indented, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All });
+
+ Assert.AreEqual(@"{
+ ""$type"": """ + productClassRef + @""",
+ ""$values"": []
+}", json);
+ }
+
+ public class CustomEnumerable<T> : IEnumerable<T>
+ {
+ //NOTE: a simple linked list
+ private readonly T value;
+ private readonly CustomEnumerable<T> next;
+ private readonly int count;
+
+ private CustomEnumerable(T value, CustomEnumerable<T> next)
+ {
+ this.value = value;
+ this.next = next;
+ count = this.next.count + 1;
+ }
+
+ public CustomEnumerable()
+ {
+ count = 0;
+ }
+
+ public CustomEnumerable<T> AddFirst(T newVal)
+ {
+ return new CustomEnumerable<T>(newVal, this);
+ }
+
+ public IEnumerator<T> GetEnumerator()
+ {
+ if (count == 0) // last node
+ yield break;
+ yield return value;
+
+ var nextInLine = next;
+ while (nextInLine != null)
+ {
+ if (nextInLine.count != 0)
+ yield return nextInLine.value;
+ nextInLine = nextInLine.next;
+ }
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return GetEnumerator();
+ }
+ }
+
}
public class Message
diff --git a/Src/Newtonsoft.Json/JsonReader.cs b/Src/Newtonsoft.Json/JsonReader.cs
index 4f37562..cf77c5d 100644
--- a/Src/Newtonsoft.Json/JsonReader.cs
+++ b/Src/Newtonsoft.Json/JsonReader.cs
@@ -346,7 +346,7 @@ namespace Newtonsoft.Json
_currentState = State.Finished;
break;
default:
- throw new JsonReaderException("While setting the reader state back to current object an unexpected JsonType was encountered: " + currentObject);
+ throw new JsonReaderException("While setting the reader state back to current object an unexpected JsonType was encountered: {0}".FormatWith(CultureInfo.InvariantCulture, currentObject));
}
}
@@ -408,7 +408,7 @@ namespace Newtonsoft.Json
case JsonToken.EndConstructor:
return JTokenType.Constructor;
default:
- throw new JsonReaderException("Not a valid close JsonToken: " + token);
+ throw new JsonReaderException("Not a valid close JsonToken: {0}".FormatWith(CultureInfo.InvariantCulture, token));
}
}
diff --git a/Src/Newtonsoft.Json/Linq/JObject.cs b/Src/Newtonsoft.Json/Linq/JObject.cs
index 308f2db..8299dfa 100644
--- a/Src/Newtonsoft.Json/Linq/JObject.cs
+++ b/Src/Newtonsoft.Json/Linq/JObject.cs
@@ -666,23 +666,19 @@ namespace Newtonsoft.Json.Linq
/// </returns>
protected override DynamicMetaObject GetMetaObject(Expression parameter)
{
- return new DynamicProxyMetaObject<JObject>(parameter, new JObjectDynamicProxy(this), true);
+ return new DynamicProxyMetaObject<JObject>(parameter, this, new JObjectDynamicProxy(), true);
}
private class JObjectDynamicProxy : DynamicProxy<JObject>
{
- public JObjectDynamicProxy(JObject value) : base(value)
- {
- }
-
- public override bool TryGetMember(GetMemberBinder binder, out object result)
+ public override bool TryGetMember(JObject instance, GetMemberBinder binder, out object result)
{
// result can be null
- result = Value[binder.Name];
+ result = instance[binder.Name];
return true;
}
- public override bool TrySetMember(SetMemberBinder binder, object value)
+ public override bool TrySetMember(JObject instance, SetMemberBinder binder, object value)
{
JToken v = value as JToken;
@@ -690,13 +686,13 @@ namespace Newtonsoft.Json.Linq
if (v == null)
v = new JValue(value);
- Value[binder.Name] = v;
+ instance[binder.Name] = v;
return true;
}
- public override IEnumerable<string> GetDynamicMemberNames()
+ public override IEnumerable<string> GetDynamicMemberNames(JObject instance)
{
- return Value.Properties().Select(p => p.Name);
+ return instance.Properties().Select(p => p.Name);
}
}
#endif
diff --git a/Src/Newtonsoft.Json/Linq/JToken.cs b/Src/Newtonsoft.Json/Linq/JToken.cs
index 796d58b..3d32300 100644
--- a/Src/Newtonsoft.Json/Linq/JToken.cs
+++ b/Src/Newtonsoft.Json/Linq/JToken.cs
@@ -1283,7 +1283,7 @@ namespace Newtonsoft.Json.Linq
/// </returns>
protected virtual DynamicMetaObject GetMetaObject(Expression parameter)
{
- return new DynamicProxyMetaObject<JToken>(parameter, new DynamicProxy<JToken>(this), true);
+ return new DynamicProxyMetaObject<JToken>(parameter, this, new DynamicProxy<JToken>(), true);
}
/// <summary>
diff --git a/Src/Newtonsoft.Json/Linq/JValue.cs b/Src/Newtonsoft.Json/Linq/JValue.cs
index 293749f..68ec283 100644
--- a/Src/Newtonsoft.Json/Linq/JValue.cs
+++ b/Src/Newtonsoft.Json/Linq/JValue.cs
@@ -29,6 +29,11 @@ using System.Linq;
using System.Text;
using Newtonsoft.Json.Utilities;
using System.Globalization;
+using System.ComponentModel;
+#if !(NET35 || NET20 || SILVERLIGHT)
+using System.Dynamic;
+using System.Linq.Expressions;
+#endif
namespace Newtonsoft.Json.Linq
{
@@ -335,13 +340,13 @@ namespace Newtonsoft.Json.Linq
internal override int GetDeepHashCode()
{
int valueHashCode = (_value != null) ? _value.GetHashCode() : 0;
-
+
return _valueType.GetHashCode() ^ valueHashCode;
}
private static bool ValuesEquals(JValue v1, JValue v2)
{
- return (v1 == v2|| (v1._valueType == v2._valueType && Compare(v1._valueType, v1._value, v2._value)));
+ return (v1 == v2 || (v1._valueType == v2._valueType && Compare(v1._valueType, v1._value, v2._value)));
}
/// <summary>
@@ -394,5 +399,51 @@ namespace Newtonsoft.Json.Linq
return _value.GetHashCode();
}
+
+#if !(NET35 || NET20 || SILVERLIGHT)
+ /// <summary>
+ /// Returns the <see cref="T:System.Dynamic.DynamicMetaObject"/> responsible for binding operations performed on this object.
+ /// </summary>
+ /// <param name="parameter">The expression tree representation of the runtime value.</param>
+ /// <returns>
+ /// The <see cref="T:System.Dynamic.DynamicMetaObject"/> to bind this object.
+ /// </returns>
+ protected override DynamicMetaObject GetMetaObject(Expression parameter)
+ {
+ return new DynamicProxyMetaObject<JValue>(parameter, this, new JValueDynamicProxy(), true);
+ }
+
+ private class JValueDynamicProxy : DynamicProxy<JValue>
+ {
+ public override bool TryConvert(JValue instance, ConvertBinder binder, out object result)
+ {
+ if (binder.Type == typeof(JValue))
+ {
+ result = instance;
+ return true;
+ }
+
+ object value = instance.Value;
+
+ if (value == null)
+ {
+ result = null;
+ return ReflectionUtils.IsNullable(binder.Type);
+ }
+
+ Type t = binder.Type;
+ if (ReflectionUtils.IsNullableType(t))
+ t = Nullable.GetUnderlyingType(t);
+
+ TypeConverter converter = TypeDescriptor.GetConverter(instance.Value);
+ if (converter != null && converter.CanConvertTo(t))
+ result = converter.ConvertTo(instance.Value, t);
+ else
+ result = Convert.ChangeType(instance.Value, t, CultureInfo.InvariantCulture);
+
+ return true;
+ }
+ }
+#endif
}
} \ No newline at end of file
diff --git a/Src/Newtonsoft.Json/Utilities/DynamicProxy.cs b/Src/Newtonsoft.Json/Utilities/DynamicProxy.cs
index cadbe93..9133bd0 100644
--- a/Src/Newtonsoft.Json/Utilities/DynamicProxy.cs
+++ b/Src/Newtonsoft.Json/Utilities/DynamicProxy.cs
@@ -10,81 +10,74 @@ namespace Newtonsoft.Json.Utilities
{
internal class DynamicProxy<T>
{
- public T Value { get; private set; }
-
- public DynamicProxy(T value)
- {
- Value = value;
- }
-
- public virtual IEnumerable<string> GetDynamicMemberNames()
+ public virtual IEnumerable<string> GetDynamicMemberNames(T instance)
{
return new string[0];
}
- public virtual bool TryBinaryOperation(BinaryOperationBinder binder, object arg, out object result)
+ public virtual bool TryBinaryOperation(T instance, BinaryOperationBinder binder, object arg, out object result)
{
result = null;
return false;
}
- public virtual bool TryConvert(ConvertBinder binder, out object result)
+ public virtual bool TryConvert(T instance, ConvertBinder binder, out object result)
{
result = null;
return false;
}
- public virtual bool TryCreateInstance(CreateInstanceBinder binder, object[] args, out object result)
+ public virtual bool TryCreateInstance(T instance, CreateInstanceBinder binder, object[] args, out object result)
{
result = null;
return false;
}
- public virtual bool TryDeleteIndex(DeleteIndexBinder binder, object[] indexes)
+ public virtual bool TryDeleteIndex(T instance, DeleteIndexBinder binder, object[] indexes)
{
return false;
}
- public virtual bool TryDeleteMember(DeleteMemberBinder binder)
+ public virtual bool TryDeleteMember(T instance, DeleteMemberBinder binder)
{
return false;
}
- public virtual bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result)
+ public virtual bool TryGetIndex(T instance, GetIndexBinder binder, object[] indexes, out object result)
{
result = null;
return false;
}
- public virtual bool TryGetMember(GetMemberBinder binder, out object result)
+ public virtual bool TryGetMember(T instance, GetMemberBinder binder, out object result)
{
result = null;
return false;
}
- public virtual bool TryInvoke(InvokeBinder binder, object[] args, out object result)
+ public virtual bool TryInvoke(T instance, InvokeBinder binder, object[] args, out object result)
{
result = null;
return false;
}
- public virtual bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
+ public virtual bool TryInvokeMember(T instance, InvokeMemberBinder binder, object[] args, out object result)
{
result = null;
return false;
}
- public virtual bool TrySetIndex(SetIndexBinder binder, object[] indexes, object value)
+ public virtual bool TrySetIndex(T instance, SetIndexBinder binder, object[] indexes, object value)
{
return false;
}
- public virtual bool TrySetMember(SetMemberBinder binder, object value)
+ public virtual bool TrySetMember(T instance, SetMemberBinder binder, object value)
{
return false;
}
- public virtual bool TryUnaryOperation(UnaryOperationBinder binder, out object result)
+ public virtual bool TryUnaryOperation(T instance, UnaryOperationBinder binder, out object result)
{
result = null;
return false;
diff --git a/Src/Newtonsoft.Json/Utilities/DynamicProxyMetaObject.cs b/Src/Newtonsoft.Json/Utilities/DynamicProxyMetaObject.cs
index 58ba434..9811198 100644
--- a/Src/Newtonsoft.Json/Utilities/DynamicProxyMetaObject.cs
+++ b/Src/Newtonsoft.Json/Utilities/DynamicProxyMetaObject.cs
@@ -13,8 +13,8 @@ namespace Newtonsoft.Json.Utilities
private readonly DynamicProxy<T> _proxy;
private readonly bool _dontFallbackFirst;
- internal DynamicProxyMetaObject(Expression expression, DynamicProxy<T> proxy, bool dontFallbackFirst)
- : base(expression, BindingRestrictions.Empty, proxy.Value)
+ internal DynamicProxyMetaObject(Expression expression, T value, DynamicProxy<T> proxy, bool dontFallbackFirst)
+ : base(expression, BindingRestrictions.Empty, value)
{
_proxy = proxy;
_dontFallbackFirst = dontFallbackFirst;
@@ -218,11 +218,11 @@ namespace Newtonsoft.Json.Utilities
//
ParameterExpression result = Expression.Parameter(typeof(object), null);
-
- Expression[] callArgs = new Expression[args.Length + 2];
- Array.Copy(args, 0, callArgs, 1, args.Length);
- callArgs[0] = Constant(binder);
- callArgs[callArgs.Length - 1] = result;
+ IList<Expression> callArgs = new List<Expression>();
+ callArgs.Add(Expression.Convert(Expression, typeof(T)));
+ callArgs.Add(Constant(binder));
+ callArgs.AddRange(args);
+ callArgs.Add(result);
DynamicMetaObject resultMO = new DynamicMetaObject(result, BindingRestrictions.Empty);
@@ -279,8 +279,12 @@ namespace Newtonsoft.Json.Utilities
// }
//
ParameterExpression result = Expression.Parameter(typeof(object), null);
- Expression[] callArgs = AddFirst(args, Constant(binder));
- callArgs[args.Length] = Expression.Assign(result, callArgs[args.Length]);
+
+ IList<Expression> callArgs = new List<Expression>();
+ callArgs.Add(Expression.Convert(Expression, typeof (T)));
+ callArgs.Add(Constant(binder));
+ callArgs.AddRange(args);
+ callArgs[args.Length + 1] = Expression.Assign(result, callArgs[args.Length + 1]);
DynamicMetaObject callDynamic = new DynamicMetaObject(
Expression.Block(
@@ -310,14 +314,6 @@ namespace Newtonsoft.Json.Utilities
return _dontFallbackFirst ? callDynamic : fallback(callDynamic);
}
- internal static TItem[] AddFirst<TItem>(IList<TItem> list, TItem item)
- {
- TItem[] res = new TItem[list.Count + 1];
- res[0] = item;
- list.CopyTo(res, 1);
- return res;
- }
-
/// <summary>
/// Helper method for generating a MetaObject which calls a
/// specific method on Dynamic, but uses one of the arguments for
@@ -331,6 +327,11 @@ namespace Newtonsoft.Json.Utilities
//
DynamicMetaObject fallbackResult = fallback(null);
+ IList<Expression> callArgs = new List<Expression>();
+ callArgs.Add(Expression.Convert(Expression, typeof(T)));
+ callArgs.Add(Constant(binder));
+ callArgs.AddRange(args);
+
//
// Build a new expression like:
// if (TryDeleteMember(payload)) { } else { fallbackResult }
@@ -340,7 +341,7 @@ namespace Newtonsoft.Json.Utilities
Expression.Call(
Expression.Constant(_proxy),
typeof(DynamicProxy<T>).GetMethod(methodName),
- AddFirst(args, Constant(binder))
+ callArgs
),
Expression.Empty(),
fallbackResult.Expression,
@@ -366,15 +367,14 @@ namespace Newtonsoft.Json.Utilities
/// </summary>
private BindingRestrictions GetRestrictions()
{
- // ReSharper disable CompareNonConstrainedGenericWithNull
- return Value == null && HasValue // ReSharper restore CompareNonConstrainedGenericWithNull
+ return (Value == null && HasValue)
? BindingRestrictions.GetInstanceRestriction(Expression, null)
: BindingRestrictions.GetTypeRestriction(Expression, LimitType);
}
public override IEnumerable<string> GetDynamicMemberNames()
{
- return _proxy.GetDynamicMemberNames();
+ return _proxy.GetDynamicMemberNames(Value);
}
// It is okay to throw NotSupported from this binder. This object