From 29567c5b5d4e48bcc4095a76eb78bc22d0f6489b Mon Sep 17 00:00:00 2001 From: Lowell Smith Date: Fri, 5 Feb 2016 15:05:42 -0500 Subject: [PATCH] Fixed an issue where iterating extensionDataGetter's enumerable multiple times or using LINQ statement on it caused inconsistant data to be returned. --- .../Serialization/ContractResolverTests.cs | 27 +++++++++++++ .../Serialization/DefaultContractResolver.cs | 38 ++++--------------- 2 files changed, 35 insertions(+), 30 deletions(-) diff --git a/Src/Newtonsoft.Json.Tests/Serialization/ContractResolverTests.cs b/Src/Newtonsoft.Json.Tests/Serialization/ContractResolverTests.cs index 6b71dd21..4f49e979 100644 --- a/Src/Newtonsoft.Json.Tests/Serialization/ContractResolverTests.cs +++ b/Src/Newtonsoft.Json.Tests/Serialization/ContractResolverTests.cs @@ -614,5 +614,32 @@ namespace Newtonsoft.Json.Tests.Serialization } #pragma warning restore 618 #endif + + public class ClassWithExtensionData + { + [JsonExtensionData] + public IDictionary Data { get; set; } + } + + [Test] + public void ExtensionDataGetterCanBeIteratedMultipleTimes() + { + var resolver = new DefaultContractResolver(); + var contract = (JsonObjectContract)resolver.ResolveContract(typeof(ClassWithExtensionData)); + + var myClass = new ClassWithExtensionData + { + Data = new Dictionary + { + { "SomeField", "Field" }, + } + }; + + var getter = contract.ExtensionDataGetter; + + var extensionData = getter(myClass); + Assert.IsTrue(extensionData.Any()); + Assert.IsTrue(extensionData.Any()); // second test fails if the enumerator returned isn't reset + } } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs b/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs index d65a4b4d..9c5ef398 100644 --- a/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs +++ b/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs @@ -576,49 +576,27 @@ namespace Newtonsoft.Json.Serialization contract.ExtensionDataValueType = valueType; } - internal struct DictionaryEnumerator : IEnumerable>, IEnumerator> + internal struct DictionaryEnumerator : IEnumerable> { - private readonly IEnumerator> _e; + private readonly IEnumerable> _e; public DictionaryEnumerator(IEnumerable> e) { ValidationUtils.ArgumentNotNull(e, nameof(e)); - _e = e.GetEnumerator(); - } - - public bool MoveNext() - { - return _e.MoveNext(); - } - - public void Reset() - { - _e.Reset(); - } - - public KeyValuePair Current - { - get { return new KeyValuePair(_e.Current.Key, _e.Current.Value); } - } - - public void Dispose() - { - _e.Dispose(); - } - - object IEnumerator.Current - { - get { return Current; } + _e = e; } public IEnumerator> GetEnumerator() { - return this; + foreach (var item in _e) + { + yield return new KeyValuePair(item.Key, item.Value); + } } IEnumerator IEnumerable.GetEnumerator() { - return this; + return GetEnumerator(); } }