diff --git a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs index 7864da5c..ff1be4c8 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs @@ -2041,9 +2041,19 @@ namespace Newtonsoft.Json.Serialization IDictionary targetDictionary = (dictionaryContract.ShouldCreateWrapper) ? dictionaryContract.CreateWrapper(createdObjectDictionary) : (IDictionary)createdObjectDictionary; IDictionary newValues = (dictionaryContract.ShouldCreateWrapper) ? dictionaryContract.CreateWrapper(value) : (IDictionary)value; - foreach (DictionaryEntry newValue in newValues) + // Manual use of IDictionaryEnumerator instead of foreach to avoid DictionaryEntry box allocations. + IDictionaryEnumerator e = newValues.GetEnumerator(); + try { - targetDictionary.Add(newValue.Key, newValue.Value); + while (e.MoveNext()) + { + DictionaryEntry entry = e.Entry; + targetDictionary.Add(entry.Key, entry.Value); + } + } + finally + { + (e as IDisposable)?.Dispose(); } } } diff --git a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs index d5b84963..6f2679e9 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs @@ -1050,49 +1050,60 @@ namespace Newtonsoft.Json.Serialization int initialDepth = writer.Top; - foreach (DictionaryEntry entry in values) + // Manual use of IDictionaryEnumerator instead of foreach to avoid DictionaryEntry box allocations. + IDictionaryEnumerator e = values.GetEnumerator(); + try { - bool escape; - string propertyName = GetPropertyName(writer, entry.Key, contract.KeyContract, out escape); - - propertyName = (contract.DictionaryKeyResolver != null) - ? contract.DictionaryKeyResolver(propertyName) - : propertyName; - - try + while (e.MoveNext()) { - object value = entry.Value; - JsonContract valueContract = contract.FinalItemContract ?? GetContractSafe(value); + DictionaryEntry entry = e.Entry; - if (ShouldWriteReference(value, null, valueContract, contract, member)) + bool escape; + string propertyName = GetPropertyName(writer, entry.Key, contract.KeyContract, out escape); + + propertyName = (contract.DictionaryKeyResolver != null) + ? contract.DictionaryKeyResolver(propertyName) + : propertyName; + + try { - writer.WritePropertyName(propertyName, escape); - WriteReference(writer, value); - } - else - { - if (!CheckForCircularReference(writer, value, null, valueContract, contract, member)) + object value = entry.Value; + JsonContract valueContract = contract.FinalItemContract ?? GetContractSafe(value); + + if (ShouldWriteReference(value, null, valueContract, contract, member)) { - continue; + writer.WritePropertyName(propertyName, escape); + WriteReference(writer, value); } + else + { + if (!CheckForCircularReference(writer, value, null, valueContract, contract, member)) + { + continue; + } - writer.WritePropertyName(propertyName, escape); + writer.WritePropertyName(propertyName, escape); - SerializeValue(writer, value, valueContract, null, contract, member); + SerializeValue(writer, value, valueContract, null, contract, member); + } } - } - catch (Exception ex) - { - if (IsErrorHandled(underlyingDictionary, contract, propertyName, null, writer.ContainerPath, ex)) + catch (Exception ex) { - HandleError(writer, initialDepth); - } - else - { - throw; + if (IsErrorHandled(underlyingDictionary, contract, propertyName, null, writer.ContainerPath, ex)) + { + HandleError(writer, initialDepth); + } + else + { + throw; + } } } } + finally + { + (e as IDisposable)?.Dispose(); + } writer.WriteEndObject(); diff --git a/Src/Newtonsoft.Json/Utilities/DictionaryWrapper.cs b/Src/Newtonsoft.Json/Utilities/DictionaryWrapper.cs index 4819c23d..4208513a 100644 --- a/Src/Newtonsoft.Json/Utilities/DictionaryWrapper.cs +++ b/Src/Newtonsoft.Json/Utilities/DictionaryWrapper.cs @@ -299,9 +299,19 @@ namespace Newtonsoft.Json.Utilities { if (_dictionary != null) { - foreach (DictionaryEntry item in _dictionary) + // Manual use of IDictionaryEnumerator instead of foreach to avoid DictionaryEntry box allocations. + IDictionaryEnumerator e = _dictionary.GetEnumerator(); + try { - array[arrayIndex++] = new KeyValuePair((TKey)item.Key, (TValue)item.Value); + while (e.MoveNext()) + { + DictionaryEntry entry = e.Entry; + array[arrayIndex++] = new KeyValuePair((TKey)entry.Key, (TValue)entry.Value); + } + } + finally + { + (e as IDisposable)?.Dispose(); } } #if !(NET40 || NET35 || NET20 || PORTABLE40)