diff --git a/Src/Newtonsoft.Json.Tests/Serialization/ContractResolverTests.cs b/Src/Newtonsoft.Json.Tests/Serialization/ContractResolverTests.cs index 6b71dd21..85b3f3ea 100644 --- a/Src/Newtonsoft.Json.Tests/Serialization/ContractResolverTests.cs +++ b/Src/Newtonsoft.Json.Tests/Serialization/ContractResolverTests.cs @@ -614,5 +614,36 @@ namespace Newtonsoft.Json.Tests.Serialization } #pragma warning restore 618 #endif + + public class ClassWithExtensionData + { + [JsonExtensionData] + public IDictionary 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 + { + { "SomeField", "Field" }, + } + }; + + ExtensionDataGetter getter = contract.ExtensionDataGetter; + + IEnumerable> dictionaryData = getter(myClass).ToDictionary(kv => kv.Key, kv => kv.Value); + Assert.IsTrue(dictionaryData.Any()); + Assert.IsTrue(dictionaryData.Any()); + + IEnumerable> 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..bf970338 100644 --- a/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs +++ b/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs @@ -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 createEnumerableWrapper = JsonTypeReflector.ReflectionDelegateFactory.CreateParameterizedConstructor(constructors); @@ -576,49 +576,29 @@ namespace Newtonsoft.Json.Serialization contract.ExtensionDataValueType = valueType; } - internal struct DictionaryEnumerator : IEnumerable>, IEnumerator> + // leave as class instead of struct + // will be always return as an interface and boxed + internal class EnumerableDictionaryWrapper : IEnumerable> { - private readonly IEnumerator> _e; + private readonly IEnumerable> _e; - public DictionaryEnumerator(IEnumerable> e) + public EnumerableDictionaryWrapper(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 (KeyValuePair item in _e) + { + yield return new KeyValuePair(item.Key, item.Value); + } } IEnumerator IEnumerable.GetEnumerator() { - return this; + return GetEnumerator(); } }