Merge branch 'MerickOWA-enumerablefix'

This commit is contained in:
James Newton-King
2016-02-06 10:50:21 +13:00
2 changed files with 43 additions and 32 deletions
@@ -614,5 +614,36 @@ namespace Newtonsoft.Json.Tests.Serialization
}
#pragma warning restore 618
#endif
public class ClassWithExtensionData
{
[JsonExtensionData]
public IDictionary<string, object> Data { get; set; }
}
[Test]
public void ExtensionDataGetterCanBeIteratedMultipleTimes()
{
DefaultContractResolver resolver = new DefaultContractResolver();
JsonObjectContract contract = (JsonObjectContract)resolver.ResolveContract(typeof(ClassWithExtensionData));
ClassWithExtensionData myClass = new ClassWithExtensionData
{
Data = new Dictionary<string, object>
{
{ "SomeField", "Field" },
}
};
ExtensionDataGetter getter = contract.ExtensionDataGetter;
IEnumerable<KeyValuePair<object, object>> dictionaryData = getter(myClass).ToDictionary(kv => kv.Key, kv => kv.Value);
Assert.IsTrue(dictionaryData.Any());
Assert.IsTrue(dictionaryData.Any());
IEnumerable<KeyValuePair<object, object>> extensionData = getter(myClass);
Assert.IsTrue(extensionData.Any());
Assert.IsTrue(extensionData.Any()); // second test fails if the enumerator returned isn't reset
}
}
}
@@ -555,7 +555,7 @@ namespace Newtonsoft.Json.Serialization
if (extensionDataAttribute.WriteData)
{
Type enumerableWrapper = typeof(DictionaryEnumerator<,>).MakeGenericType(keyType, valueType);
Type enumerableWrapper = typeof(EnumerableDictionaryWrapper<,>).MakeGenericType(keyType, valueType);
ConstructorInfo constructors = enumerableWrapper.GetConstructors().First();
ObjectConstructor<object> createEnumerableWrapper = JsonTypeReflector.ReflectionDelegateFactory.CreateParameterizedConstructor(constructors);
@@ -576,49 +576,29 @@ namespace Newtonsoft.Json.Serialization
contract.ExtensionDataValueType = valueType;
}
internal struct DictionaryEnumerator<TEnumeratorKey, TEnumeratorValue> : IEnumerable<KeyValuePair<object, object>>, IEnumerator<KeyValuePair<object, object>>
// leave as class instead of struct
// will be always return as an interface and boxed
internal class EnumerableDictionaryWrapper<TEnumeratorKey, TEnumeratorValue> : IEnumerable<KeyValuePair<object, object>>
{
private readonly IEnumerator<KeyValuePair<TEnumeratorKey, TEnumeratorValue>> _e;
private readonly IEnumerable<KeyValuePair<TEnumeratorKey, TEnumeratorValue>> _e;
public DictionaryEnumerator(IEnumerable<KeyValuePair<TEnumeratorKey, TEnumeratorValue>> e)
public EnumerableDictionaryWrapper(IEnumerable<KeyValuePair<TEnumeratorKey, TEnumeratorValue>> e)
{
ValidationUtils.ArgumentNotNull(e, nameof(e));
_e = e.GetEnumerator();
}
public bool MoveNext()
{
return _e.MoveNext();
}
public void Reset()
{
_e.Reset();
}
public KeyValuePair<object, object> Current
{
get { return new KeyValuePair<object, object>(_e.Current.Key, _e.Current.Value); }
}
public void Dispose()
{
_e.Dispose();
}
object IEnumerator.Current
{
get { return Current; }
_e = e;
}
public IEnumerator<KeyValuePair<object, object>> GetEnumerator()
{
return this;
foreach (KeyValuePair<TEnumeratorKey, TEnumeratorValue> item in _e)
{
yield return new KeyValuePair<object, object>(item.Key, item.Value);
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return this;
return GetEnumerator();
}
}