diff options
author | JamesNK <james@newtonking.com> | 2010-11-25 10:11:38 +0300 |
---|---|---|
committer | JamesNK <james@newtonking.com> | 2010-11-25 10:11:38 +0300 |
commit | efc2310a3dbcfbd6820dd57ad62ffa473258f5bc (patch) | |
tree | 0d62a86f0c9196dc035c961946ddccf84f756324 /Src/Newtonsoft.Json | |
parent | 5c0431464be353671d2c3b9607018fbf34045657 (diff) |
-Make .NET 4.0 dynamic actually work (oops)
-Added JValue dynamic value conversion
Diffstat (limited to 'Src/Newtonsoft.Json')
-rw-r--r-- | Src/Newtonsoft.Json/JsonReader.cs | 4 | ||||
-rw-r--r-- | Src/Newtonsoft.Json/Linq/JObject.cs | 18 | ||||
-rw-r--r-- | Src/Newtonsoft.Json/Linq/JToken.cs | 2 | ||||
-rw-r--r-- | Src/Newtonsoft.Json/Linq/JValue.cs | 55 | ||||
-rw-r--r-- | Src/Newtonsoft.Json/Utilities/DynamicProxy.cs | 33 | ||||
-rw-r--r-- | Src/Newtonsoft.Json/Utilities/DynamicProxyMetaObject.cs | 42 |
6 files changed, 97 insertions, 57 deletions
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
|