-Performance
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
@@ -15,14 +16,35 @@ namespace Newtonsoft.Json.TestConsole
|
||||
Console.ReadKey();
|
||||
Console.WriteLine("Doing stuff...");
|
||||
|
||||
PerformanceTests t = new PerformanceTests();
|
||||
//PerformanceTests t = new PerformanceTests();
|
||||
//t.DeserializeLargeJson();
|
||||
|
||||
//t.BenchmarkSerializeMethod(PerformanceTests.SerializeMethod.JsonNet, new { hello = "world" });
|
||||
t.DeserializeLargeJson();
|
||||
WriteLargeJson();
|
||||
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("Finished");
|
||||
Console.WriteLine("Press any key to exit");
|
||||
Console.ReadKey();
|
||||
}
|
||||
|
||||
public static void WriteLargeJson()
|
||||
{
|
||||
var json = System.IO.File.ReadAllText("large.json");
|
||||
|
||||
IList<PerformanceTests.RootObject> o = JsonConvert.DeserializeObject<IList<PerformanceTests.RootObject>>(json);
|
||||
|
||||
Console.WriteLine("Press any key to start serialize");
|
||||
Console.ReadKey();
|
||||
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
using (StreamWriter file = System.IO.File.CreateText("largewrite.json"))
|
||||
{
|
||||
JsonSerializer serializer = new JsonSerializer();
|
||||
serializer.Formatting = Formatting.Indented;
|
||||
serializer.Serialize(file, o);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,4 +33,4 @@ using System.Runtime.InteropServices;
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("6.0.0.0")]
|
||||
[assembly: AssemblyVersion("6.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("6.0.5.17725")]
|
||||
[assembly: AssemblyFileVersion("6.0.5.17728")]
|
||||
|
||||
@@ -82,6 +82,60 @@ namespace Newtonsoft.Json.Tests
|
||||
}
|
||||
}
|
||||
|
||||
public class NameTableTestClass
|
||||
{
|
||||
public string Value { get; set; }
|
||||
}
|
||||
|
||||
public class NameTableTestClassConverter : JsonConverter
|
||||
{
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
{
|
||||
reader.Read();
|
||||
reader.Read();
|
||||
|
||||
JsonTextReader jsonTextReader = (JsonTextReader)reader;
|
||||
Assert.IsNotNull(jsonTextReader.NameTable);
|
||||
|
||||
string s = serializer.Deserialize<string>(reader);
|
||||
Assert.AreEqual("hi", s);
|
||||
Assert.IsNotNull(jsonTextReader.NameTable);
|
||||
|
||||
NameTableTestClass o = new NameTableTestClass
|
||||
{
|
||||
Value = s
|
||||
};
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return objectType == typeof(NameTableTestClass);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void NameTableTest()
|
||||
{
|
||||
StringReader sr = new StringReader("{'property':'hi'}");
|
||||
JsonTextReader jsonTextReader = new JsonTextReader(sr);
|
||||
|
||||
Assert.IsNull(jsonTextReader.NameTable);
|
||||
|
||||
JsonSerializer serializer = new JsonSerializer();
|
||||
serializer.Converters.Add(new NameTableTestClassConverter());
|
||||
NameTableTestClass o = serializer.Deserialize<NameTableTestClass>(jsonTextReader);
|
||||
|
||||
Assert.IsNull(jsonTextReader.NameTable);
|
||||
Assert.AreEqual("hi", o.Value);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DefaultSettings_Example()
|
||||
{
|
||||
|
||||
@@ -160,7 +160,7 @@ namespace Newtonsoft.Json.Tests
|
||||
public Guid guid { get; set; }
|
||||
public bool isActive { get; set; }
|
||||
public string balance { get; set; }
|
||||
public string picture { get; set; }
|
||||
public Uri picture { get; set; }
|
||||
public int age { get; set; }
|
||||
public string eyeColor { get; set; }
|
||||
public string name { get; set; }
|
||||
@@ -170,7 +170,7 @@ namespace Newtonsoft.Json.Tests
|
||||
public string phone { get; set; }
|
||||
public string address { get; set; }
|
||||
public string about { get; set; }
|
||||
public string registered { get; set; }
|
||||
public DateTime registered { get; set; }
|
||||
public double latitude { get; set; }
|
||||
public decimal longitude { get; set; }
|
||||
public List<string> tags { get; set; }
|
||||
@@ -182,15 +182,9 @@ namespace Newtonsoft.Json.Tests
|
||||
[Test]
|
||||
public void DeserializeLargeJson()
|
||||
{
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
using (var fs = System.IO.File.OpenText("large.json"))
|
||||
using (JsonTextReader jsonTextReader = new JsonTextReader(fs))
|
||||
{
|
||||
JsonSerializer serializer = new JsonSerializer();
|
||||
serializer.Deserialize<IList<RootObject>>(jsonTextReader);
|
||||
}
|
||||
}
|
||||
var json = System.IO.File.ReadAllText("large.json");
|
||||
|
||||
BenchmarkDeserializeMethod<IList<RootObject>>(SerializeMethod.JsonNet, json, 100, false);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -812,15 +806,18 @@ If attributes are not mentioned, default values are used in each case.
|
||||
#endregion
|
||||
|
||||
#region Deserialize
|
||||
public void BenchmarkDeserializeMethod<T>(SerializeMethod method, object json)
|
||||
public void BenchmarkDeserializeMethod<T>(SerializeMethod method, object json, int? iterations = null, bool warmUp = true)
|
||||
{
|
||||
Deserialize<T>(method, json);
|
||||
if (warmUp)
|
||||
Deserialize<T>(method, json);
|
||||
|
||||
Stopwatch timed = new Stopwatch();
|
||||
timed.Start();
|
||||
|
||||
iterations = iterations ?? Iterations;
|
||||
|
||||
T value = default(T);
|
||||
for (int x = 0; x < Iterations; x++)
|
||||
for (int x = 0; x < iterations.Value; x++)
|
||||
{
|
||||
value = Deserialize<T>(method, json);
|
||||
}
|
||||
@@ -950,15 +947,14 @@ If attributes are not mentioned, default values are used in each case.
|
||||
|
||||
public T DeserializeWebExtensions<T>(string json)
|
||||
{
|
||||
JavaScriptSerializer ser = new JavaScriptSerializer();
|
||||
JavaScriptSerializer ser = new JavaScriptSerializer { MaxJsonLength = int.MaxValue };
|
||||
|
||||
return ser.Deserialize<T>(json);
|
||||
}
|
||||
|
||||
public T DeserializeDataContractJson<T>(string json)
|
||||
{
|
||||
DataContractJsonSerializer dataContractSerializer
|
||||
= new DataContractJsonSerializer(typeof(T));
|
||||
DataContractJsonSerializer dataContractSerializer = new DataContractJsonSerializer(typeof(T));
|
||||
|
||||
MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(json));
|
||||
|
||||
|
||||
@@ -74,4 +74,4 @@ using System.Security;
|
||||
// by using the '*' as shown below:
|
||||
|
||||
[assembly: AssemblyVersion("6.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("6.0.5.17725")]
|
||||
[assembly: AssemblyFileVersion("6.0.5.17728")]
|
||||
|
||||
@@ -36,7 +36,6 @@ using Newtonsoft.Json.Utilities;
|
||||
using Newtonsoft.Json.Utilities.LinqBridge;
|
||||
#else
|
||||
using System.Linq;
|
||||
|
||||
#endif
|
||||
|
||||
namespace Newtonsoft.Json.Converters
|
||||
|
||||
@@ -355,15 +355,17 @@ namespace Newtonsoft.Json
|
||||
|
||||
internal static string ToString(Guid value, char quoteChar)
|
||||
{
|
||||
string text = null;
|
||||
|
||||
string text;
|
||||
string qc;
|
||||
#if !(NETFX_CORE || PORTABLE40 || PORTABLE)
|
||||
text = value.ToString("D", CultureInfo.InvariantCulture);
|
||||
qc = quoteChar.ToString(CultureInfo.InvariantCulture);
|
||||
#else
|
||||
text = value.ToString("D");
|
||||
qc = quoteChar.ToString();
|
||||
#endif
|
||||
|
||||
return quoteChar + text + quoteChar;
|
||||
return qc + text + qc;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -778,6 +778,14 @@ namespace Newtonsoft.Json
|
||||
{
|
||||
previousDateFormatString = null;
|
||||
}
|
||||
|
||||
JsonTextReader textReader = reader as JsonTextReader;
|
||||
if (textReader != null)
|
||||
{
|
||||
DefaultContractResolver resolver = _contractResolver as DefaultContractResolver;
|
||||
if (resolver != null)
|
||||
textReader.NameTable = resolver.GetState().NameTable;
|
||||
}
|
||||
}
|
||||
|
||||
private void ResetReader(JsonReader reader, CultureInfo previousCulture, DateTimeZoneHandling? previousDateTimeZoneHandling, DateParseHandling? previousDateParseHandling, FloatParseHandling? previousFloatParseHandling, int? previousMaxDepth, string previousDateFormatString)
|
||||
@@ -795,6 +803,10 @@ namespace Newtonsoft.Json
|
||||
reader.MaxDepth = previousMaxDepth;
|
||||
if (_dateFormatStringSet)
|
||||
reader.DateFormatString = previousDateFormatString;
|
||||
|
||||
JsonTextReader textReader = reader as JsonTextReader;
|
||||
if (textReader != null)
|
||||
textReader.NameTable = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -29,7 +29,6 @@ using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
using System.Xml;
|
||||
using System.Globalization;
|
||||
using Newtonsoft.Json.Utilities;
|
||||
|
||||
@@ -65,6 +64,7 @@ namespace Newtonsoft.Json
|
||||
private bool _isEndOfFile;
|
||||
private StringBuffer _buffer;
|
||||
private StringReference _stringReference;
|
||||
internal PropertyNameTable NameTable;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="JsonReader"/> class with the specified <see cref="TextReader"/>.
|
||||
@@ -174,7 +174,7 @@ namespace Newtonsoft.Json
|
||||
|
||||
private void ShiftBufferIfNeeded()
|
||||
{
|
||||
// once in the last 10% of the buffer shift the remainling content to the start to avoid
|
||||
// once in the last 10% of the buffer shift the remaining content to the start to avoid
|
||||
// unnessesarly increasing the buffer size when reading numbers/strings
|
||||
int length = _chars.Length;
|
||||
if (length - _charPos <= length * 0.1)
|
||||
@@ -844,7 +844,20 @@ namespace Newtonsoft.Json
|
||||
throw JsonReaderException.Create(this, "Invalid property identifier character: {0}.".FormatWith(CultureInfo.InvariantCulture, _chars[_charPos]));
|
||||
}
|
||||
|
||||
string propertyName = _stringReference.ToString();
|
||||
string propertyName;
|
||||
|
||||
if (NameTable != null)
|
||||
{
|
||||
propertyName = NameTable.Get(_stringReference.Chars, _stringReference.StartIndex, _stringReference.Length);
|
||||
|
||||
// no match in name table
|
||||
if (propertyName == null)
|
||||
propertyName = _stringReference.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
propertyName = _stringReference.ToString();
|
||||
}
|
||||
|
||||
EatWhitespace(false);
|
||||
|
||||
|
||||
@@ -49,6 +49,7 @@ namespace Newtonsoft.Json
|
||||
private bool _quoteName;
|
||||
private bool[] _charEscapeFlags;
|
||||
private char[] _writeBuffer;
|
||||
private char[] _indentChars;
|
||||
|
||||
private Base64Encoder Base64Encoder
|
||||
{
|
||||
@@ -98,7 +99,14 @@ namespace Newtonsoft.Json
|
||||
public char IndentChar
|
||||
{
|
||||
get { return _indentChar; }
|
||||
set { _indentChar = value; }
|
||||
set
|
||||
{
|
||||
if (value != _indentChar)
|
||||
{
|
||||
_indentChar = value;
|
||||
_indentChars = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -266,14 +274,19 @@ namespace Newtonsoft.Json
|
||||
// levels of indentation multiplied by the indent count
|
||||
int currentIndentCount = Top * _indentation;
|
||||
|
||||
while (currentIndentCount > 0)
|
||||
if (currentIndentCount > 0)
|
||||
{
|
||||
// write up to a max of 10 characters at once to avoid creating too many new strings
|
||||
int writeCount = Math.Min(currentIndentCount, 10);
|
||||
if (_indentChars == null)
|
||||
_indentChars = new string(_indentChar, 10).ToCharArray();
|
||||
|
||||
_writer.Write(new string(_indentChar, writeCount));
|
||||
while (currentIndentCount > 0)
|
||||
{
|
||||
int writeCount = Math.Min(currentIndentCount, 10);
|
||||
|
||||
currentIndentCount -= writeCount;
|
||||
_writer.Write(_indentChars, 0, writeCount);
|
||||
|
||||
currentIndentCount -= writeCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -620,7 +633,18 @@ namespace Newtonsoft.Json
|
||||
public override void WriteValue(Guid value)
|
||||
{
|
||||
InternalWriteValue(JsonToken.String);
|
||||
WriteValueInternal(JsonConvert.ToString(value, _quoteChar), JsonToken.String);
|
||||
|
||||
string text = null;
|
||||
|
||||
#if !(NETFX_CORE || PORTABLE40 || PORTABLE)
|
||||
text = value.ToString("D", CultureInfo.InvariantCulture);
|
||||
#else
|
||||
text = value.ToString("D");
|
||||
#endif
|
||||
|
||||
_writer.Write(_quoteChar);
|
||||
_writer.Write(text);
|
||||
_writer.Write(_quoteChar);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -630,7 +654,17 @@ namespace Newtonsoft.Json
|
||||
public override void WriteValue(TimeSpan value)
|
||||
{
|
||||
InternalWriteValue(JsonToken.String);
|
||||
WriteValueInternal(JsonConvert.ToString(value, _quoteChar), JsonToken.String);
|
||||
|
||||
string text;
|
||||
#if (NET35 || NET20)
|
||||
text = value.ToString();
|
||||
#else
|
||||
text = value.ToString(null, CultureInfo.InvariantCulture);
|
||||
#endif
|
||||
|
||||
_writer.Write(_quoteChar);
|
||||
_writer.Write(text);
|
||||
_writer.Write(_quoteChar);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -646,7 +680,7 @@ namespace Newtonsoft.Json
|
||||
else
|
||||
{
|
||||
InternalWriteValue(JsonToken.String);
|
||||
WriteValueInternal(JsonConvert.ToString(value, _quoteChar), JsonToken.String);
|
||||
WriteEscapedString(value.OriginalString, true);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -234,6 +234,7 @@
|
||||
<Compile Include="Utilities\ILGeneratorExtensions.cs" />
|
||||
<Compile Include="Utilities\LateBoundReflectionDelegateFactory.cs" />
|
||||
<Compile Include="Utilities\MethodCall.cs" />
|
||||
<Compile Include="Utilities\PropertyNameTable.cs" />
|
||||
<Compile Include="Utilities\ReflectionDelegateFactory.cs" />
|
||||
<Compile Include="Utilities\ReflectionObject.cs" />
|
||||
<Compile Include="Utilities\StringReference.cs" />
|
||||
|
||||
@@ -245,6 +245,7 @@
|
||||
<Compile Include="Utilities\ILGeneratorExtensions.cs" />
|
||||
<Compile Include="Utilities\ImmutableCollectionsUtils.cs" />
|
||||
<Compile Include="Utilities\LinqBridge.cs" />
|
||||
<Compile Include="Utilities\PropertyNameTable.cs" />
|
||||
<Compile Include="Utilities\ReflectionDelegateFactory.cs" />
|
||||
<Compile Include="Utilities\LateBoundReflectionDelegateFactory.cs" />
|
||||
<Compile Include="Utilities\MethodCall.cs" />
|
||||
|
||||
@@ -245,6 +245,7 @@
|
||||
<Compile Include="Utilities\ILGeneratorExtensions.cs" />
|
||||
<Compile Include="Utilities\ImmutableCollectionsUtils.cs" />
|
||||
<Compile Include="Utilities\LinqBridge.cs" />
|
||||
<Compile Include="Utilities\PropertyNameTable.cs" />
|
||||
<Compile Include="Utilities\ReflectionDelegateFactory.cs" />
|
||||
<Compile Include="Utilities\LateBoundReflectionDelegateFactory.cs" />
|
||||
<Compile Include="Utilities\MethodCall.cs" />
|
||||
|
||||
@@ -221,6 +221,7 @@
|
||||
<Compile Include="Utilities\MathUtils.cs" />
|
||||
<Compile Include="Utilities\MethodCall.cs" />
|
||||
<Compile Include="Utilities\MiscellaneousUtils.cs" />
|
||||
<Compile Include="Utilities\PropertyNameTable.cs" />
|
||||
<Compile Include="Utilities\ReflectionDelegateFactory.cs" />
|
||||
<Compile Include="Utilities\ReflectionObject.cs" />
|
||||
<Compile Include="Utilities\ReflectionUtils.cs" />
|
||||
|
||||
@@ -225,6 +225,7 @@
|
||||
<Compile Include="Utilities\MathUtils.cs" />
|
||||
<Compile Include="Utilities\MethodCall.cs" />
|
||||
<Compile Include="Utilities\MiscellaneousUtils.cs" />
|
||||
<Compile Include="Utilities\PropertyNameTable.cs" />
|
||||
<Compile Include="Utilities\ReflectionDelegateFactory.cs" />
|
||||
<Compile Include="Utilities\ReflectionObject.cs" />
|
||||
<Compile Include="Utilities\ReflectionUtils.cs" />
|
||||
|
||||
@@ -213,6 +213,7 @@
|
||||
<Compile Include="Utilities\DynamicProxyMetaObject.cs" />
|
||||
<Compile Include="Utilities\DynamicReflectionDelegateFactory.cs" />
|
||||
<Compile Include="Utilities\DynamicUtils.cs" />
|
||||
<Compile Include="Utilities\PropertyNameTable.cs" />
|
||||
<Compile Include="Utilities\ReflectionObject.cs" />
|
||||
<Compile Include="Utilities\EnumUtils.cs" />
|
||||
<Compile Include="Utilities\EnumValue.cs" />
|
||||
|
||||
@@ -91,5 +91,5 @@ using System.Security;
|
||||
// by using the '*' as shown below:
|
||||
|
||||
[assembly: AssemblyVersion("6.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("6.0.5.17725")]
|
||||
[assembly: AssemblyFileVersion("6.0.5.17728")]
|
||||
[assembly: CLSCompliant(true)]
|
||||
|
||||
@@ -83,6 +83,12 @@ namespace Newtonsoft.Json.Serialization
|
||||
}
|
||||
}
|
||||
|
||||
internal class DefaultContractResolverState
|
||||
{
|
||||
public Dictionary<ResolverContractKey, JsonContract> ContractCache;
|
||||
public PropertyNameTable NameTable = new PropertyNameTable();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used by <see cref="JsonSerializer"/> to resolves a <see cref="JsonContract"/> for a given <see cref="Type"/>.
|
||||
/// </summary>
|
||||
@@ -122,10 +128,10 @@ namespace Newtonsoft.Json.Serialization
|
||||
new RegexConverter()
|
||||
};
|
||||
|
||||
private static Dictionary<ResolverContractKey, JsonContract> _sharedContractCache;
|
||||
private static readonly object _typeContractCacheLock = new object();
|
||||
private static readonly object TypeContractCacheLock = new object();
|
||||
|
||||
private Dictionary<ResolverContractKey, JsonContract> _instanceContractCache;
|
||||
private static readonly DefaultContractResolverState _sharedState = new DefaultContractResolverState();
|
||||
private readonly DefaultContractResolverState _instanceState = new DefaultContractResolverState();
|
||||
private readonly bool _sharedCache;
|
||||
|
||||
/// <summary>
|
||||
@@ -190,9 +196,9 @@ namespace Newtonsoft.Json.Serialization
|
||||
/// </summary>
|
||||
/// <param name="shareCache">
|
||||
/// If set to <c>true</c> the <see cref="DefaultContractResolver"/> will use a cached shared with other resolvers of the same type.
|
||||
/// Sharing the cache will significantly performance because expensive reflection will only happen once but could cause unexpected
|
||||
/// behavior if different instances of the resolver are suppose to produce different results. When set to false it is highly
|
||||
/// recommended to reuse <see cref="DefaultContractResolver"/> instances with the <see cref="JsonSerializer"/>.
|
||||
/// Sharing the cache will significantly improve performance with multiple resolver instances because expensive reflection will only
|
||||
/// happen once. This setting can cause unexpected behavior if different instances of the resolver are suppose to produce different
|
||||
/// results. When set to false it is highly recommended to reuse <see cref="DefaultContractResolver"/> instances with the <see cref="JsonSerializer"/>.
|
||||
/// </param>
|
||||
public DefaultContractResolver(bool shareCache)
|
||||
{
|
||||
@@ -208,20 +214,12 @@ namespace Newtonsoft.Json.Serialization
|
||||
_sharedCache = shareCache;
|
||||
}
|
||||
|
||||
private Dictionary<ResolverContractKey, JsonContract> GetCache()
|
||||
internal DefaultContractResolverState GetState()
|
||||
{
|
||||
if (_sharedCache)
|
||||
return _sharedContractCache;
|
||||
return _sharedState;
|
||||
else
|
||||
return _instanceContractCache;
|
||||
}
|
||||
|
||||
private void UpdateCache(Dictionary<ResolverContractKey, JsonContract> cache)
|
||||
{
|
||||
if (_sharedCache)
|
||||
_sharedContractCache = cache;
|
||||
else
|
||||
_instanceContractCache = cache;
|
||||
return _instanceState;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -234,24 +232,25 @@ namespace Newtonsoft.Json.Serialization
|
||||
if (type == null)
|
||||
throw new ArgumentNullException("type");
|
||||
|
||||
DefaultContractResolverState state = GetState();
|
||||
|
||||
JsonContract contract;
|
||||
ResolverContractKey key = new ResolverContractKey(GetType(), type);
|
||||
Dictionary<ResolverContractKey, JsonContract> cache = GetCache();
|
||||
Dictionary<ResolverContractKey, JsonContract> cache = state.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)
|
||||
lock (TypeContractCacheLock)
|
||||
{
|
||||
cache = GetCache();
|
||||
Dictionary<ResolverContractKey, JsonContract> updatedCache =
|
||||
(cache != null)
|
||||
? new Dictionary<ResolverContractKey, JsonContract>(cache)
|
||||
: new Dictionary<ResolverContractKey, JsonContract>();
|
||||
cache = state.ContractCache;
|
||||
Dictionary<ResolverContractKey, JsonContract> updatedCache = (cache != null)
|
||||
? new Dictionary<ResolverContractKey, JsonContract>(cache)
|
||||
: new Dictionary<ResolverContractKey, JsonContract>();
|
||||
updatedCache[key] = contract;
|
||||
|
||||
UpdateCache(updatedCache);
|
||||
state.ContractCache = updatedCache;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1111,7 +1110,17 @@ namespace Newtonsoft.Json.Serialization
|
||||
JsonProperty property = CreateProperty(member, memberSerialization);
|
||||
|
||||
if (property != null)
|
||||
{
|
||||
DefaultContractResolverState state = GetState();
|
||||
|
||||
// nametable is not thread-safe for multiple writers
|
||||
lock (state.NameTable)
|
||||
{
|
||||
property.PropertyName = state.NameTable.Add(property.PropertyName);
|
||||
}
|
||||
|
||||
properties.AddProperty(property);
|
||||
}
|
||||
}
|
||||
|
||||
IList<JsonProperty> orderedProperties = properties.OrderBy(p => p.Order ?? -1).ToList();
|
||||
|
||||
@@ -0,0 +1,160 @@
|
||||
#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
|
||||
|
||||
using System;
|
||||
|
||||
namespace Newtonsoft.Json.Utilities
|
||||
{
|
||||
internal class PropertyNameTable
|
||||
{
|
||||
// used to defeat hashtable DoS attack where someone passes in lots of strings that hash to the same hash code
|
||||
private static readonly int HashCodeRandomizer;
|
||||
|
||||
private int _count;
|
||||
private Entry[] _entries;
|
||||
private int _mask = 31;
|
||||
|
||||
static PropertyNameTable()
|
||||
{
|
||||
HashCodeRandomizer = Environment.TickCount;
|
||||
}
|
||||
|
||||
public PropertyNameTable()
|
||||
{
|
||||
_entries = new Entry[_mask + 1];
|
||||
}
|
||||
|
||||
public string Get(char[] key, int start, int length)
|
||||
{
|
||||
if (length == 0)
|
||||
return string.Empty;
|
||||
|
||||
int hashCode = length + HashCodeRandomizer;
|
||||
hashCode += (hashCode << 7) ^ key[start];
|
||||
int end = start + length;
|
||||
for (int i = start + 1; i < end; i++)
|
||||
{
|
||||
hashCode += (hashCode << 7) ^ key[i];
|
||||
}
|
||||
hashCode -= hashCode >> 17;
|
||||
hashCode -= hashCode >> 11;
|
||||
hashCode -= hashCode >> 5;
|
||||
for (Entry entry = _entries[hashCode & _mask]; entry != null; entry = entry.Next)
|
||||
{
|
||||
if (entry.HashCode == hashCode && TextEquals(entry.Value, key, start, length))
|
||||
return entry.Value;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public string Add(string key)
|
||||
{
|
||||
if (key == null)
|
||||
throw new ArgumentNullException("key");
|
||||
|
||||
int length = key.Length;
|
||||
if (length == 0)
|
||||
return string.Empty;
|
||||
|
||||
int hashCode = length + HashCodeRandomizer;
|
||||
for (int i = 0; i < key.Length; i++)
|
||||
{
|
||||
hashCode += (hashCode << 7) ^ key[i];
|
||||
}
|
||||
hashCode -= hashCode >> 17;
|
||||
hashCode -= hashCode >> 11;
|
||||
hashCode -= hashCode >> 5;
|
||||
for (Entry entry = _entries[hashCode & _mask]; entry != null; entry = entry.Next)
|
||||
{
|
||||
if (entry.HashCode == hashCode && entry.Value.Equals(key))
|
||||
return entry.Value;
|
||||
}
|
||||
|
||||
return AddEntry(key, hashCode);
|
||||
}
|
||||
|
||||
|
||||
private string AddEntry(string str, int hashCode)
|
||||
{
|
||||
int index = hashCode & _mask;
|
||||
Entry entry = new Entry(str, hashCode, _entries[index]);
|
||||
_entries[index] = entry;
|
||||
if (_count++ == _mask)
|
||||
{
|
||||
Grow();
|
||||
}
|
||||
return entry.Value;
|
||||
}
|
||||
|
||||
private void Grow()
|
||||
{
|
||||
Entry[] entries = _entries;
|
||||
int newMask = (_mask * 2) + 1;
|
||||
Entry[] newEntries = new Entry[newMask + 1];
|
||||
|
||||
for (int i = 0; i < entries.Length; i++)
|
||||
{
|
||||
Entry next;
|
||||
for (Entry entry = entries[i]; entry != null; entry = next)
|
||||
{
|
||||
int index = entry.HashCode & newMask;
|
||||
next = entry.Next;
|
||||
entry.Next = newEntries[index];
|
||||
newEntries[index] = entry;
|
||||
}
|
||||
}
|
||||
_entries = newEntries;
|
||||
_mask = newMask;
|
||||
}
|
||||
|
||||
private static bool TextEquals(string str1, char[] str2, int str2Start, int str2Length)
|
||||
{
|
||||
if (str1.Length != str2Length)
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < str1.Length; i++)
|
||||
{
|
||||
if (str1[i] != str2[str2Start + i])
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private class Entry
|
||||
{
|
||||
internal readonly string Value;
|
||||
internal readonly int HashCode;
|
||||
internal Entry Next;
|
||||
|
||||
internal Entry(string value, int hashCode, Entry next)
|
||||
{
|
||||
Value = value;
|
||||
HashCode = hashCode;
|
||||
Next = next;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user