diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.csproj index 717a8304..1d117a77 100644 --- a/Src/Newtonsoft.Json/Newtonsoft.Json.csproj +++ b/Src/Newtonsoft.Json/Newtonsoft.Json.csproj @@ -34,11 +34,11 @@ Json.NET - HAVE_ADO_NET;HAVE_APP_DOMAIN;HAVE_ASYNC;HAVE_BIG_INTEGER;HAVE_BINARY_FORMATTER;HAVE_BINARY_SERIALIZATION;HAVE_BINARY_EXCEPTION_SERIALIZATION;HAVE_CAS;HAVE_CHAR_TO_LOWER_WITH_CULTURE;HAVE_CHAR_TO_STRING_WITH_CULTURE;HAVE_COM_ATTRIBUTES;HAVE_COMPONENT_MODEL;HAVE_CONCURRENT_COLLECTIONS;HAVE_COVARIANT_GENERICS;HAVE_DATA_CONTRACTS;HAVE_DATE_TIME_OFFSET;HAVE_DB_NULL_TYPE_CODE;HAVE_DYNAMIC;HAVE_EMPTY_TYPES;HAVE_ENTITY_FRAMEWORK;HAVE_EXPRESSIONS;HAVE_FSHARP_TYPES;HAVE_FULL_REFLECTION;HAVE_GUID_TRY_PARSE;HAVE_HASH_SET;HAVE_ICLONEABLE;HAVE_ICONVERTIBLE;HAVE_IGNORE_DATA_MEMBER_ATTRIBUTE;HAVE_IMMUTABLE_COLLECTIONS;HAVE_INOTIFY_COLLECTION_CHANGED;HAVE_INOTIFY_PROPERTY_CHANGING;HAVE_ISET;HAVE_LINQ;HAVE_MEMORY_BARRIER;HAVE_METHOD_IMPL_ATTRIBUTE;HAVE_NON_SERIALIZED_ATTRIBUTE;HAVE_READ_ONLY_COLLECTIONS;HAVE_REFLECTION_EMIT;HAVE_SECURITY_SAFE_CRITICAL_ATTRIBUTE;HAVE_SERIALIZATION_BINDER_BIND_TO_NAME;HAVE_STREAM_READER_WRITER_CLOSE;HAVE_STRING_JOIN_WITH_ENUMERABLE;HAVE_TIME_SPAN_PARSE_WITH_CULTURE;HAVE_TIME_SPAN_TO_STRING_WITH_CULTURE;HAVE_TIME_ZONE_INFO;HAVE_TRACE_WRITER;HAVE_TYPE_DESCRIPTOR;HAVE_UNICODE_SURROGATE_DETECTION;HAVE_VARIANT_TYPE_PARAMETERS;HAVE_VERSION_TRY_PARSE;HAVE_XLINQ;HAVE_XML_DOCUMENT;HAVE_XML_DOCUMENT_TYPE;$(AdditionalConstants) + HAVE_ADO_NET;HAVE_APP_DOMAIN;HAVE_ASYNC;HAVE_BIG_INTEGER;HAVE_BINARY_FORMATTER;HAVE_BINARY_SERIALIZATION;HAVE_BINARY_EXCEPTION_SERIALIZATION;HAVE_CAS;HAVE_CHAR_TO_LOWER_WITH_CULTURE;HAVE_CHAR_TO_STRING_WITH_CULTURE;HAVE_COM_ATTRIBUTES;HAVE_COMPONENT_MODEL;HAVE_CONCURRENT_COLLECTIONS;HAVE_COVARIANT_GENERICS;HAVE_DATA_CONTRACTS;HAVE_DATE_TIME_OFFSET;HAVE_DB_NULL_TYPE_CODE;HAVE_DYNAMIC;HAVE_EMPTY_TYPES;HAVE_ENTITY_FRAMEWORK;HAVE_EXPRESSIONS;HAVE_FSHARP_TYPES;HAVE_FULL_REFLECTION;HAVE_GUID_TRY_PARSE;HAVE_HASH_SET;HAVE_ICLONEABLE;HAVE_ICONVERTIBLE;HAVE_IGNORE_DATA_MEMBER_ATTRIBUTE;HAVE_IMMUTABLE_COLLECTIONS;HAVE_INOTIFY_COLLECTION_CHANGED;HAVE_INOTIFY_PROPERTY_CHANGING;HAVE_ISET;HAVE_LINQ;HAVE_MEMORY_BARRIER;HAVE_METHOD_IMPL_ATTRIBUTE;HAVE_NON_SERIALIZED_ATTRIBUTE;HAVE_READ_ONLY_COLLECTIONS;HAVE_REFLECTION_EMIT;HAVE_SECURITY_SAFE_CRITICAL_ATTRIBUTE;HAVE_SERIALIZATION_BINDER_BIND_TO_NAME;HAVE_STREAM_READER_WRITER_CLOSE;HAVE_STRING_JOIN_WITH_ENUMERABLE;HAVE_TIME_SPAN_PARSE_WITH_CULTURE;HAVE_TIME_SPAN_TO_STRING_WITH_CULTURE;HAVE_TIME_ZONE_INFO;HAVE_TRACE_WRITER;HAVE_TYPE_DESCRIPTOR;HAVE_UNICODE_SURROGATE_DETECTION;HAVE_VARIANT_TYPE_PARAMETERS;HAVE_VERSION_TRY_PARSE;HAVE_XLINQ;HAVE_XML_DOCUMENT;HAVE_XML_DOCUMENT_TYPE;HAVE_CONCURRENT_DICTIONARY;$(AdditionalConstants) Json.NET .NET 4.0 - NET40;HAVE_ADO_NET;HAVE_APP_DOMAIN;HAVE_BIG_INTEGER;HAVE_BINARY_FORMATTER;HAVE_BINARY_SERIALIZATION;HAVE_BINARY_EXCEPTION_SERIALIZATION;HAVE_CAS;HAVE_CHAR_TO_STRING_WITH_CULTURE;HAVE_CHAR_TO_LOWER_WITH_CULTURE;HAVE_COM_ATTRIBUTES;HAVE_COMPONENT_MODEL;HAVE_CONCURRENT_COLLECTIONS;HAVE_COVARIANT_GENERICS;HAVE_DATA_CONTRACTS;HAVE_DATE_TIME_OFFSET;HAVE_DB_NULL_TYPE_CODE;HAVE_DYNAMIC;HAVE_EMPTY_TYPES;HAVE_ENTITY_FRAMEWORK;HAVE_EXPRESSIONS;HAVE_FSHARP_TYPES;HAVE_FULL_REFLECTION;HAVE_GUID_TRY_PARSE;HAVE_HASH_SET;HAVE_ICLONEABLE;HAVE_ICONVERTIBLE;HAVE_IGNORE_DATA_MEMBER_ATTRIBUTE;HAVE_INOTIFY_COLLECTION_CHANGED;HAVE_INOTIFY_PROPERTY_CHANGING;HAVE_ISET;HAVE_LINQ;HAVE_MEMORY_BARRIER;HAVE_NON_SERIALIZED_ATTRIBUTE;HAVE_REFLECTION_EMIT;HAVE_SECURITY_SAFE_CRITICAL_ATTRIBUTE;HAVE_SERIALIZATION_BINDER_BIND_TO_NAME;HAVE_STREAM_READER_WRITER_CLOSE;HAVE_STRING_JOIN_WITH_ENUMERABLE;HAVE_TIME_SPAN_PARSE_WITH_CULTURE;HAVE_TIME_SPAN_TO_STRING_WITH_CULTURE;HAVE_TIME_ZONE_INFO;HAVE_TRACE_WRITER;HAVE_TYPE_DESCRIPTOR;HAVE_UNICODE_SURROGATE_DETECTION;HAVE_VARIANT_TYPE_PARAMETERS;HAVE_VERSION_TRY_PARSE;HAVE_XLINQ;HAVE_XML_DOCUMENT;HAVE_XML_DOCUMENT_TYPE;$(AdditionalConstants) + NET40;HAVE_ADO_NET;HAVE_APP_DOMAIN;HAVE_BIG_INTEGER;HAVE_BINARY_FORMATTER;HAVE_BINARY_SERIALIZATION;HAVE_BINARY_EXCEPTION_SERIALIZATION;HAVE_CAS;HAVE_CHAR_TO_STRING_WITH_CULTURE;HAVE_CHAR_TO_LOWER_WITH_CULTURE;HAVE_COM_ATTRIBUTES;HAVE_COMPONENT_MODEL;HAVE_CONCURRENT_COLLECTIONS;HAVE_COVARIANT_GENERICS;HAVE_DATA_CONTRACTS;HAVE_DATE_TIME_OFFSET;HAVE_DB_NULL_TYPE_CODE;HAVE_DYNAMIC;HAVE_EMPTY_TYPES;HAVE_ENTITY_FRAMEWORK;HAVE_EXPRESSIONS;HAVE_FSHARP_TYPES;HAVE_FULL_REFLECTION;HAVE_GUID_TRY_PARSE;HAVE_HASH_SET;HAVE_ICLONEABLE;HAVE_ICONVERTIBLE;HAVE_IGNORE_DATA_MEMBER_ATTRIBUTE;HAVE_INOTIFY_COLLECTION_CHANGED;HAVE_INOTIFY_PROPERTY_CHANGING;HAVE_ISET;HAVE_LINQ;HAVE_MEMORY_BARRIER;HAVE_NON_SERIALIZED_ATTRIBUTE;HAVE_REFLECTION_EMIT;HAVE_SECURITY_SAFE_CRITICAL_ATTRIBUTE;HAVE_SERIALIZATION_BINDER_BIND_TO_NAME;HAVE_STREAM_READER_WRITER_CLOSE;HAVE_STRING_JOIN_WITH_ENUMERABLE;HAVE_TIME_SPAN_PARSE_WITH_CULTURE;HAVE_TIME_SPAN_TO_STRING_WITH_CULTURE;HAVE_TIME_ZONE_INFO;HAVE_TRACE_WRITER;HAVE_TYPE_DESCRIPTOR;HAVE_UNICODE_SURROGATE_DETECTION;HAVE_VARIANT_TYPE_PARAMETERS;HAVE_VERSION_TRY_PARSE;HAVE_XLINQ;HAVE_XML_DOCUMENT;HAVE_XML_DOCUMENT_TYPE;HAVE_CONCURRENT_DICTIONARY;$(AdditionalConstants) Json.NET .NET 3.5 @@ -63,7 +63,7 @@ Json.NET .NET Standard 1.3 - NETSTANDARD1_3;PORTABLE;HAVE_ASYNC;HAVE_BIG_INTEGER;HAVE_BINARY_SERIALIZATION;HAVE_COVARIANT_GENERICS;HAVE_DATA_CONTRACTS;HAVE_DATE_TIME_OFFSET;HAVE_DYNAMIC;HAVE_EXPRESSIONS;HAVE_FSHARP_TYPES;HAVE_GUID_TRY_PARSE;HAVE_HASH_SET;HAVE_IGNORE_DATA_MEMBER_ATTRIBUTE;HAVE_IMMUTABLE_COLLECTIONS;HAVE_INOTIFY_COLLECTION_CHANGED;HAVE_ISET;HAVE_LINQ;HAVE_METHOD_IMPL_ATTRIBUTE;HAVE_NON_SERIALIZED_ATTRIBUTE;HAVE_READ_ONLY_COLLECTIONS;HAVE_REFLECTION_BINDER;HAVE_SERIALIZATION_BINDER_BIND_TO_NAME;HAVE_STRING_JOIN_WITH_ENUMERABLE;HAVE_TIME_SPAN_PARSE_WITH_CULTURE;HAVE_TIME_SPAN_TO_STRING_WITH_CULTURE;HAVE_TIME_ZONE_INFO;HAVE_TYPE_DESCRIPTOR;HAVE_UNICODE_SURROGATE_DETECTION;HAVE_VARIANT_TYPE_PARAMETERS;HAVE_VERSION_TRY_PARSE;HAVE_XLINQ;HAVE_OBSOLETE_FORMATTER_ASSEMBLY_STYLE;HAVE_XML_DOCUMENT;$(AdditionalConstants) + NETSTANDARD1_3;PORTABLE;HAVE_ASYNC;HAVE_BIG_INTEGER;HAVE_BINARY_SERIALIZATION;HAVE_COVARIANT_GENERICS;HAVE_DATA_CONTRACTS;HAVE_DATE_TIME_OFFSET;HAVE_DYNAMIC;HAVE_EXPRESSIONS;HAVE_FSHARP_TYPES;HAVE_GUID_TRY_PARSE;HAVE_HASH_SET;HAVE_IGNORE_DATA_MEMBER_ATTRIBUTE;HAVE_IMMUTABLE_COLLECTIONS;HAVE_INOTIFY_COLLECTION_CHANGED;HAVE_ISET;HAVE_LINQ;HAVE_METHOD_IMPL_ATTRIBUTE;HAVE_NON_SERIALIZED_ATTRIBUTE;HAVE_READ_ONLY_COLLECTIONS;HAVE_REFLECTION_BINDER;HAVE_SERIALIZATION_BINDER_BIND_TO_NAME;HAVE_STRING_JOIN_WITH_ENUMERABLE;HAVE_TIME_SPAN_PARSE_WITH_CULTURE;HAVE_TIME_SPAN_TO_STRING_WITH_CULTURE;HAVE_TIME_ZONE_INFO;HAVE_TYPE_DESCRIPTOR;HAVE_UNICODE_SURROGATE_DETECTION;HAVE_VARIANT_TYPE_PARAMETERS;HAVE_VERSION_TRY_PARSE;HAVE_XLINQ;HAVE_OBSOLETE_FORMATTER_ASSEMBLY_STYLE;HAVE_XML_DOCUMENT;HAVE_CONCURRENT_DICTIONARY;$(AdditionalConstants) Json.NET Portable .NET 4.0 diff --git a/Src/Newtonsoft.Json/Serialization/CamelCasePropertyNamesContractResolver.cs b/Src/Newtonsoft.Json/Serialization/CamelCasePropertyNamesContractResolver.cs index d093f622..324d08b1 100644 --- a/Src/Newtonsoft.Json/Serialization/CamelCasePropertyNamesContractResolver.cs +++ b/Src/Newtonsoft.Json/Serialization/CamelCasePropertyNamesContractResolver.cs @@ -24,6 +24,9 @@ #endregion using System; +#if HAVE_CONCURRENT_DICTIONARY +using System.Collections.Concurrent; +#endif using System.Collections.Generic; using System.Globalization; using Newtonsoft.Json.Utilities; @@ -69,7 +72,7 @@ namespace Newtonsoft.Json.Serialization { private static readonly object TypeContractCacheLock = new object(); private static readonly PropertyNameTable NameTable = new PropertyNameTable(); - private static Dictionary _contractCache; + private static readonly ConcurrentDictionary _contractCache = new ConcurrentDictionary(); /// /// Initializes a new instance of the class. @@ -96,27 +99,8 @@ namespace Newtonsoft.Json.Serialization } // for backwards compadibility the CamelCasePropertyNamesContractResolver shares contracts between instances - JsonContract contract; ResolverContractKey key = new ResolverContractKey(GetType(), type); - Dictionary cache = _contractCache; - if (cache == null || !cache.TryGetValue(key, out contract)) - { - contract = CreateContract(type); - - // avoid the possibility of modifying the cache dictionary while another thread is accessing it - lock (TypeContractCacheLock) - { - cache = _contractCache; - Dictionary updatedCache = (cache != null) - ? new Dictionary(cache) - : new Dictionary(); - updatedCache[key] = contract; - - _contractCache = updatedCache; - } - } - - return contract; + return _contractCache.GetOrAdd(key, k => CreateContract(type)); } internal override PropertyNameTable GetNameTable() diff --git a/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs b/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs index d5e840f3..575ed346 100644 --- a/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs +++ b/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs @@ -25,6 +25,9 @@ using System; using System.Collections; +#if HAVE_CONCURRENT_DICTIONARY +using System.Collections.Concurrent; +#endif using Newtonsoft.Json.Schema; using System.Collections.Generic; using System.ComponentModel; @@ -47,6 +50,7 @@ using Newtonsoft.Json.Utilities.LinqBridge; using System.Linq; #endif +using Newtonsoft.Json.Serialization; namespace Newtonsoft.Json.Serialization { @@ -92,7 +96,7 @@ namespace Newtonsoft.Json.Serialization private readonly object _typeContractCacheLock = new object(); private readonly PropertyNameTable _nameTable = new PropertyNameTable(); - private Dictionary _contractCache; + private readonly ConcurrentDictionary _contractCache = new ConcurrentDictionary(); /// /// Gets a value indicating whether members are being get and set using dynamic code generation. @@ -175,26 +179,7 @@ namespace Newtonsoft.Json.Serialization throw new ArgumentNullException(nameof(type)); } - JsonContract contract; - Dictionary cache = _contractCache; - if (cache == null || !cache.TryGetValue(type, out contract)) - { - contract = CreateContract(type); - - // avoid the possibility of modifying the cache dictionary while another thread is accessing it - lock (_typeContractCacheLock) - { - cache = _contractCache; - Dictionary updatedCache = (cache != null) - ? new Dictionary(cache) - : new Dictionary(); - updatedCache[type] = contract; - - _contractCache = updatedCache; - } - } - - return contract; + return _contractCache.GetOrAdd(type, CreateContract); } /// diff --git a/Src/Newtonsoft.Json/Utilities/ConcurrentDictionary.cs b/Src/Newtonsoft.Json/Utilities/ConcurrentDictionary.cs new file mode 100644 index 00000000..be1b89a8 --- /dev/null +++ b/Src/Newtonsoft.Json/Utilities/ConcurrentDictionary.cs @@ -0,0 +1,76 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +#if !HAVE_CONCURRENT_DICTIONARY + +using System; +using System.Collections.Generic; +using System.Threading; + +namespace Newtonsoft.Json.Serialization +{ + internal sealed class ConcurrentDictionary + { + private readonly object _lock = new object(); + private Dictionary _dictionary = new Dictionary(); + + public TValue GetOrAdd(TKey key, Func valueFactory) + { + TValue value; + if (!_dictionary.TryGetValue(key, out value)) + { + return AddValue(key, valueFactory); + } + + return value; + } + + private TValue AddValue(TKey key, Func valueFactory) + { + TValue value = valueFactory(key); + + lock (_lock) + { + // double check locking + TValue checkValue; + if (_dictionary.TryGetValue(key, out checkValue)) + { + return checkValue; + } + + Dictionary newDictionary = new Dictionary(_dictionary); + newDictionary[key] = value; + +#if HAVE_MEMORY_BARRIER + Thread.MemoryBarrier(); +#endif + _dictionary = newDictionary; + } + + return value; + } + } +} +#endif \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Utilities/ThreadSafeStore.cs b/Src/Newtonsoft.Json/Utilities/ThreadSafeStore.cs index 89a94dc8..0ab83dcf 100644 --- a/Src/Newtonsoft.Json/Utilities/ThreadSafeStore.cs +++ b/Src/Newtonsoft.Json/Utilities/ThreadSafeStore.cs @@ -24,19 +24,16 @@ #endregion using System; -using System.Collections.Generic; -#if !HAVE_LINQ -using Newtonsoft.Json.Utilities.LinqBridge; +#if HAVE_CONCURRENT_DICTIONARY +using System.Collections.Concurrent; #endif -using System.Threading; using Newtonsoft.Json.Serialization; namespace Newtonsoft.Json.Utilities { internal class ThreadSafeStore { - private readonly object _lock = new object(); - private Dictionary _store; + private readonly ConcurrentDictionary _store; private readonly Func _creator; public ThreadSafeStore(Func creator) @@ -47,51 +44,12 @@ namespace Newtonsoft.Json.Utilities } _creator = creator; - _store = new Dictionary(); + _store = new ConcurrentDictionary(); } public TValue Get(TKey key) { - TValue value; - if (!_store.TryGetValue(key, out value)) - { - return AddValue(key); - } - - return value; - } - - private TValue AddValue(TKey key) - { - TValue value = _creator(key); - - lock (_lock) - { - if (_store == null) - { - _store = new Dictionary(); - _store[key] = value; - } - else - { - // double check locking - TValue checkValue; - if (_store.TryGetValue(key, out checkValue)) - { - return checkValue; - } - - Dictionary newStore = new Dictionary(_store); - newStore[key] = value; - -#if HAVE_MEMORY_BARRIER - Thread.MemoryBarrier(); -#endif - _store = newStore; - } - - return value; - } + return _store.GetOrAdd(key, _creator); } } } \ No newline at end of file