Skip to content

Commit

Permalink
-Fixed bad performance with dynamic
Browse files Browse the repository at this point in the history
-Added support for creating collections with an IEnumerable<T> constructor
  • Loading branch information
JamesNK committed Mar 11, 2013
1 parent 92de187 commit 0e75388
Show file tree
Hide file tree
Showing 10 changed files with 179 additions and 95 deletions.
2 changes: 1 addition & 1 deletion Src/Newtonsoft.Json.Tests/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,4 +73,4 @@
// 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("4.5.11.15906")]
[assembly: AssemblyFileVersion("4.5.11.15911")]
5 changes: 4 additions & 1 deletion Src/Newtonsoft.Json.Tests/Serialization/DynamicTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,13 @@ public void SerializeDynamicObject()

Dictionary<string, object> values = new Dictionary<string, object>();

IContractResolver c = DefaultContractResolver.Instance;
JsonDynamicContract dynamicContract = (JsonDynamicContract)c.ResolveContract(dynamicObject.GetType());

foreach (string memberName in dynamicObject.GetDynamicMemberNames())
{
object value;
dynamicObject.TryGetMember(memberName, out value);
dynamicContract.TryGetMember(dynamicObject, memberName, out value);

values.Add(memberName, value);
}
Expand Down
37 changes: 37 additions & 0 deletions Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6513,6 +6513,43 @@ public void SerializeKeyValuePairConverterWithCamelCase()
}", json);
}

public class EnumerableClass<T> : IEnumerable<T>
{
private readonly IList<T> _values;

public EnumerableClass(IEnumerable<T> values)
{
_values = new List<T>(values);
}

public IEnumerator<T> GetEnumerator()
{
return _values.GetEnumerator();
}

IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}

[Test]
public void DeserializeIEnumerableFromConstructor()
{
string json = @"[
""One"",
""II"",
""3""
]";

var result = JsonConvert.DeserializeObject<EnumerableClass<string>>(json);

Assert.AreEqual(3, result.Count());
Assert.AreEqual("One", result.ElementAt(0));
Assert.AreEqual("II", result.ElementAt(1));
Assert.AreEqual("3", result.ElementAt(2));
}

[JsonObject(MemberSerialization.Fields)]
public class MyTuple<T1>
{
Expand Down
9 changes: 2 additions & 7 deletions Src/Newtonsoft.Json/Converters/XmlNodeConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -974,16 +974,14 @@ private void SerializeNode(JsonWriter writer, IXmlNode node, XmlNamespaceManager
{
manager.PushScope();

string namespacePrefix = null;
string namespaceUri = null;
foreach (IXmlNode attribute in node.Attributes)
{
if (attribute.NamespaceUri == "http://www.w3.org/2000/xmlns/")
{
namespacePrefix = (attribute.LocalName != "xmlns")
string namespacePrefix = (attribute.LocalName != "xmlns")
? attribute.LocalName
: string.Empty;
namespaceUri = attribute.Value;
string namespaceUri = attribute.Value;

manager.AddNamespace(namespacePrefix, namespaceUri);
}
Expand Down Expand Up @@ -1017,9 +1015,6 @@ private void SerializeNode(JsonWriter writer, IXmlNode node, XmlNamespaceManager
writer.WriteEndObject();
}

if (namespacePrefix != null)
manager.RemoveNamespace(namespacePrefix, namespaceUri);

manager.PopScope();
}

Expand Down
2 changes: 1 addition & 1 deletion Src/Newtonsoft.Json/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,6 @@
// 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("4.5.11.15906")]
[assembly: AssemblyFileVersion("4.5.11.15911")]

[assembly: CLSCompliant(true)]
53 changes: 53 additions & 0 deletions Src/Newtonsoft.Json/Serialization/JsonDynamicContract.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@
#if !(NET35 || NET20 || WINDOWS_PHONE)
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Reflection;
using System.Runtime.CompilerServices;
using Newtonsoft.Json.Utilities;
using System.Collections;

Expand All @@ -49,6 +51,26 @@ public class JsonDynamicContract : JsonContainerContract
/// <value>The property name resolver.</value>
public Func<string, string> PropertyNameResolver { get; set; }

private readonly ThreadSafeStore<string, CallSite<Func<CallSite, object, object>>> _callSiteGetters =
new ThreadSafeStore<string, CallSite<Func<CallSite, object, object>>>(CreateCallSiteGetter);

private readonly ThreadSafeStore<string, CallSite<Func<CallSite, object, object, object>>> _callSiteSetters =
new ThreadSafeStore<string, CallSite<Func<CallSite, object, object, object>>>(CreateCallSiteSetter);

private static CallSite<Func<CallSite, object, object>> CreateCallSiteGetter(string name)
{
GetMemberBinder getMemberBinder = (GetMemberBinder)DynamicUtils.BinderWrapper.GetMember(name, typeof(DynamicUtils));

return CallSite<Func<CallSite, object, object>>.Create(new NoThrowGetBinderMember(getMemberBinder));
}

private static CallSite<Func<CallSite, object, object, object>> CreateCallSiteSetter(string name)
{
SetMemberBinder binder = (SetMemberBinder)DynamicUtils.BinderWrapper.SetMember(name, typeof(DynamicUtils));

return CallSite<Func<CallSite, object, object, object>>.Create(new NoThrowSetBinderMember(binder));
}

/// <summary>
/// Initializes a new instance of the <see cref="JsonDynamicContract"/> class.
/// </summary>
Expand All @@ -60,6 +82,37 @@ public JsonDynamicContract(Type underlyingType)

Properties = new JsonPropertyCollection(UnderlyingType);
}

internal bool TryGetMember(IDynamicMetaObjectProvider dynamicProvider, string name, out object value)
{
ValidationUtils.ArgumentNotNull(dynamicProvider, "dynamicProvider");

CallSite<Func<CallSite, object, object>> callSite = _callSiteGetters.Get(name);

object result = callSite.Target(callSite, dynamicProvider);

if (!ReferenceEquals(result, NoThrowExpressionVisitor.ErrorResult))
{
value = result;
return true;
}
else
{
value = null;
return false;
}
}

internal bool TrySetMember(IDynamicMetaObjectProvider dynamicProvider, string name, object value)
{
ValidationUtils.ArgumentNotNull(dynamicProvider, "dynamicProvider");

CallSite<Func<CallSite, object, object, object>> callSite = _callSiteSetters.Get(name);

object result = callSite.Target(callSite, dynamicProvider, value);

return !ReferenceEquals(result, NoThrowExpressionVisitor.ErrorResult);
}
}
}
#endif
Original file line number Diff line number Diff line change
Expand Up @@ -593,6 +593,10 @@ private object CreateList(JsonReader reader, Type objectType, JsonContract contr
{
list = (IList) ReflectionUtils.CreateInstance(contract.CreatedType, list);
}
else
{
return ReflectionUtils.CreateInstance(contract.CreatedType, list);
}
}
else if (list is IWrappedCollection)
{
Expand All @@ -610,6 +614,7 @@ private object CreateList(JsonReader reader, Type objectType, JsonContract contr
{
value = CreateJToken(reader, contract);
}

return value;
}

Expand Down Expand Up @@ -1263,7 +1268,7 @@ private object CreateDynamic(JsonReader reader, JsonDynamicContract contract, Js
else
value = CreateValueInternal(reader, t, dynamicMemberContract, null, null, member, null);

newObject.TrySetMember(memberName, value);
contract.TrySetMember(newObject, memberName, value);
}
}
catch (Exception ex)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -749,7 +749,7 @@ private void SerializeDynamic(JsonWriter writer, IDynamicMetaObjectProvider valu
foreach (string memberName in value.GetDynamicMemberNames())
{
object memberValue;
if (value.TryGetMember(memberName, out memberValue))
if (contract.TryGetMember(value, memberName, out memberValue))
{
try
{
Expand Down
26 changes: 26 additions & 0 deletions Src/Newtonsoft.Json/Utilities/CollectionUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,32 @@ public static IList CreateList(Type listType, out bool isReadOnlyOrFixedSize)
else
list = null;
}
else if (ReflectionUtils.ImplementsGenericDefinition(listType, typeof (IEnumerable<>), out collectionType))
{
bool suitableConstructor = false;

foreach (ConstructorInfo constructor in listType.GetConstructors())
{
IList<ParameterInfo> parameters = constructor.GetParameters();

if (parameters.Count == 1)
{
if (collectionType.IsAssignableFrom(parameters[0].ParameterType))
{
suitableConstructor = true;
break;
}
}
}

if (!suitableConstructor)
throw new Exception("{0} does not have a public constructor that takes a type that implements {1}.".FormatWith(CultureInfo.InvariantCulture, listType, collectionType));

Type collectionContentsType = collectionType.GetGenericArguments()[0];

list = CreateGenericList(collectionContentsType);
isReadOnlyOrFixedSize = true;
}
else
{
list = null;
Expand Down
Loading

0 comments on commit 0e75388

Please sign in to comment.