New features:
Added Skip() method to JsonReader. Skips the current JSON token and any child tokens.
JsonSerializer now has the ability to populate existing members on an object. This behaviour is controlled by the ObjectCreationHandling property.
Changes:
Improved behaviour of JsonReader.Depth property.
Fixes:
Floating point numbers now use ToString("r") to avoid an overflow error when serializing and deserializing a boundary value.
JsonSerializer now correctly serializes and deserializes DBNull.
JsonSerializer no longer errors when skipping a multi-token JSON structure.
This commit is contained in:
@@ -118,6 +118,30 @@ namespace Newtonsoft.Json.Tests
|
||||
White
|
||||
}
|
||||
|
||||
public class ClassWithArray
|
||||
{
|
||||
private readonly IList<long> bar;
|
||||
private string foo;
|
||||
|
||||
public ClassWithArray()
|
||||
{
|
||||
bar = new List<Int64>() { int.MaxValue };
|
||||
}
|
||||
|
||||
[JsonProperty("foo")]
|
||||
public string Foo
|
||||
{
|
||||
get { return foo; }
|
||||
set { foo = value; }
|
||||
}
|
||||
|
||||
[JsonProperty("bar")]
|
||||
public IList<long> Bar
|
||||
{
|
||||
get { return bar; }
|
||||
}
|
||||
}
|
||||
|
||||
public class JsonSerializerTest : TestFixtureBase
|
||||
{
|
||||
[Test]
|
||||
@@ -311,6 +335,9 @@ namespace Newtonsoft.Json.Tests
|
||||
{
|
||||
get { return _ignoredProperty; }
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public Product IgnoredObject = new Product();
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -320,7 +347,7 @@ namespace Newtonsoft.Json.Tests
|
||||
|
||||
Assert.AreEqual(@"{""Field"":0,""Property"":21}", json);
|
||||
|
||||
JsonIgnoreAttributeTestClass c = JavaScriptConvert.DeserializeObject<JsonIgnoreAttributeTestClass>(@"{""Field"":99,""Property"":-1,""IgnoredField"":-1}");
|
||||
JsonIgnoreAttributeTestClass c = JavaScriptConvert.DeserializeObject<JsonIgnoreAttributeTestClass>(@"{""Field"":99,""Property"":-1,""IgnoredField"":-1,""IgnoredObject"":[1,2,3,4,5]}");
|
||||
|
||||
Assert.AreEqual(0, c.IgnoredField);
|
||||
Assert.AreEqual(99, c.Field);
|
||||
@@ -780,5 +807,112 @@ keyword such as type of business.""
|
||||
string json = JavaScriptConvert.SerializeObject(null);
|
||||
Assert.AreEqual("null", json);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CanDeserializeIntArrayWhenNotFirstPropertyInJson()
|
||||
{
|
||||
string json = "{foo:'hello',bar:[1,2,3]}";
|
||||
ClassWithArray wibble = JavaScriptConvert.DeserializeObject<ClassWithArray>(json);
|
||||
Assert.AreEqual("hello", wibble.Foo);
|
||||
|
||||
Assert.AreEqual(4, wibble.Bar.Count);
|
||||
Assert.AreEqual(int.MaxValue, wibble.Bar[0]);
|
||||
Assert.AreEqual(1, wibble.Bar[1]);
|
||||
Assert.AreEqual(2, wibble.Bar[2]);
|
||||
Assert.AreEqual(3, wibble.Bar[3]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CanDeserializeIntArray_WhenArrayIsFirstPropertyInJson()
|
||||
{
|
||||
string json = "{bar:[1,2,3], foo:'hello'}";
|
||||
ClassWithArray wibble = JavaScriptConvert.DeserializeObject<ClassWithArray>(json);
|
||||
Assert.AreEqual("hello", wibble.Foo);
|
||||
|
||||
Assert.AreEqual(4, wibble.Bar.Count);
|
||||
Assert.AreEqual(int.MaxValue, wibble.Bar[0]);
|
||||
Assert.AreEqual(1, wibble.Bar[1]);
|
||||
Assert.AreEqual(2, wibble.Bar[2]);
|
||||
Assert.AreEqual(3, wibble.Bar[3]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ObjectCreationHandlingReplace()
|
||||
{
|
||||
string json = "{bar:[1,2,3], foo:'hello'}";
|
||||
|
||||
JsonSerializer s = new JsonSerializer();
|
||||
s.ObjectCreationHandling = ObjectCreationHandling.Replace;
|
||||
|
||||
ClassWithArray wibble = (ClassWithArray)s.Deserialize(new StringReader(json), typeof(ClassWithArray));
|
||||
|
||||
Assert.AreEqual("hello", wibble.Foo);
|
||||
|
||||
Assert.AreEqual(1, wibble.Bar.Count);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CanDeserializeSerializedJson()
|
||||
{
|
||||
ClassWithArray wibble = new ClassWithArray();
|
||||
wibble.Foo = "hello";
|
||||
wibble.Bar.Add(1);
|
||||
wibble.Bar.Add(2);
|
||||
wibble.Bar.Add(3);
|
||||
string json = JavaScriptConvert.SerializeObject(wibble);
|
||||
|
||||
ClassWithArray wibbleOut = JavaScriptConvert.DeserializeObject<ClassWithArray>(json);
|
||||
Assert.AreEqual("hello", wibbleOut.Foo);
|
||||
|
||||
Assert.AreEqual(5, wibbleOut.Bar.Count);
|
||||
Assert.AreEqual(int.MaxValue, wibbleOut.Bar[0]);
|
||||
Assert.AreEqual(int.MaxValue, wibbleOut.Bar[1]);
|
||||
Assert.AreEqual(1, wibbleOut.Bar[2]);
|
||||
Assert.AreEqual(2, wibbleOut.Bar[3]);
|
||||
Assert.AreEqual(3, wibbleOut.Bar[4]);
|
||||
}
|
||||
|
||||
public class ConverableMembers
|
||||
{
|
||||
public string String = "string";
|
||||
public int Int32 = int.MaxValue;
|
||||
public uint UInt32 = uint.MaxValue;
|
||||
public byte Byte = byte.MaxValue;
|
||||
public sbyte SByte = sbyte.MaxValue;
|
||||
public short Short = short.MaxValue;
|
||||
public ushort UShort = ushort.MaxValue;
|
||||
public long Long = long.MaxValue;
|
||||
public ulong ULong = long.MaxValue;
|
||||
public double Double = double.MaxValue;
|
||||
public float Float = float.MaxValue;
|
||||
public DBNull DBNull = DBNull.Value;
|
||||
public bool Bool = true;
|
||||
public char Char = '\0';
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SerializeConverableObjects()
|
||||
{
|
||||
string json = JavaScriptConvert.SerializeObject(new ConverableMembers());
|
||||
|
||||
Assert.AreEqual(@"{""String"":""string"",""Int32"":2147483647,""UInt32"":4294967295,""Byte"":255,""SByte"":127,""Short"":32767,""UShort"":65535,""Long"":9223372036854775807,""ULong"":9223372036854775807,""Double"":1.7976931348623157E+308,""Float"":3.40282347E+38,""DBNull"":null,""Bool"":true,""Char"":""\u0000""}", json);
|
||||
|
||||
ConverableMembers c = JavaScriptConvert.DeserializeObject<ConverableMembers>(json);
|
||||
Assert.AreEqual("string", c.String);
|
||||
Assert.AreEqual(double.MaxValue, c.Double);
|
||||
Assert.AreEqual(DBNull.Value, c.DBNull);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SerializeStack()
|
||||
{
|
||||
Stack s = new Stack();
|
||||
s.Push(1);
|
||||
s.Push(2);
|
||||
s.Push(3);
|
||||
|
||||
string json = JavaScriptConvert.SerializeObject(s);
|
||||
Assert.AreEqual("[3,2,1]", json);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -120,6 +120,57 @@ namespace Newtonsoft.Json.Tests
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Depth()
|
||||
{
|
||||
string input = "{value:'Purple\\r \\n monkey\\'s:\\tdishwasher',array:[1,2]}";
|
||||
|
||||
StringReader sr = new StringReader(input);
|
||||
|
||||
using (JsonReader jsonReader = new JsonTextReader(sr))
|
||||
{
|
||||
Assert.AreEqual(0, jsonReader.Depth);
|
||||
|
||||
jsonReader.Read();
|
||||
Assert.AreEqual(jsonReader.TokenType, JsonToken.StartObject);
|
||||
Assert.AreEqual(0, jsonReader.Depth);
|
||||
|
||||
jsonReader.Read();
|
||||
Assert.AreEqual(jsonReader.TokenType, JsonToken.PropertyName);
|
||||
Assert.AreEqual(1, jsonReader.Depth);
|
||||
|
||||
jsonReader.Read();
|
||||
Assert.AreEqual(jsonReader.TokenType, JsonToken.String);
|
||||
Assert.AreEqual(jsonReader.Value, "Purple\r \n monkey's:\tdishwasher");
|
||||
Assert.AreEqual(jsonReader.QuoteChar, '\'');
|
||||
Assert.AreEqual(1, jsonReader.Depth);
|
||||
|
||||
jsonReader.Read();
|
||||
Assert.AreEqual(jsonReader.TokenType, JsonToken.PropertyName);
|
||||
Assert.AreEqual(1, jsonReader.Depth);
|
||||
|
||||
jsonReader.Read();
|
||||
Assert.AreEqual(jsonReader.TokenType, JsonToken.StartArray);
|
||||
Assert.AreEqual(2, jsonReader.Depth);
|
||||
|
||||
jsonReader.Read();
|
||||
Assert.AreEqual(jsonReader.TokenType, JsonToken.Integer);
|
||||
Assert.AreEqual(3, jsonReader.Depth);
|
||||
|
||||
jsonReader.Read();
|
||||
Assert.AreEqual(jsonReader.TokenType, JsonToken.Integer);
|
||||
Assert.AreEqual(3, jsonReader.Depth);
|
||||
|
||||
jsonReader.Read();
|
||||
Assert.AreEqual(jsonReader.TokenType, JsonToken.EndArray);
|
||||
Assert.AreEqual(1, jsonReader.Depth);
|
||||
|
||||
jsonReader.Read();
|
||||
Assert.AreEqual(jsonReader.TokenType, JsonToken.EndObject);
|
||||
Assert.AreEqual(0, jsonReader.Depth);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ReadingEscapedStrings()
|
||||
{
|
||||
@@ -129,19 +180,25 @@ namespace Newtonsoft.Json.Tests
|
||||
|
||||
using (JsonReader jsonReader = new JsonTextReader(sr))
|
||||
{
|
||||
Assert.AreEqual(0, jsonReader.Depth);
|
||||
|
||||
jsonReader.Read();
|
||||
Assert.AreEqual(jsonReader.TokenType, JsonToken.StartObject);
|
||||
Assert.AreEqual(0, jsonReader.Depth);
|
||||
|
||||
jsonReader.Read();
|
||||
Assert.AreEqual(jsonReader.TokenType, JsonToken.PropertyName);
|
||||
Assert.AreEqual(1, jsonReader.Depth);
|
||||
|
||||
jsonReader.Read();
|
||||
Assert.AreEqual(jsonReader.TokenType, JsonToken.String);
|
||||
Assert.AreEqual(jsonReader.Value, "Purple\r \n monkey's:\tdishwasher");
|
||||
Assert.AreEqual(jsonReader.QuoteChar, '\'');
|
||||
Assert.AreEqual(1, jsonReader.Depth);
|
||||
|
||||
jsonReader.Read();
|
||||
Assert.AreEqual(jsonReader.TokenType, JsonToken.EndObject);
|
||||
Assert.AreEqual(0, jsonReader.Depth);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -252,7 +252,7 @@ namespace Newtonsoft.Json
|
||||
/// <returns>A Json string representation of the <see cref="Single"/>.</returns>
|
||||
public static string ToString(float value)
|
||||
{
|
||||
return value.ToString(null, CultureInfo.InvariantCulture);
|
||||
return value.ToString("R", CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -262,7 +262,7 @@ namespace Newtonsoft.Json
|
||||
/// <returns>A Json string representation of the <see cref="Double"/>.</returns>
|
||||
public static string ToString(double value)
|
||||
{
|
||||
return value.ToString(null, CultureInfo.InvariantCulture);
|
||||
return value.ToString("R", CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -107,7 +107,14 @@ namespace Newtonsoft.Json
|
||||
|
||||
public int Depth
|
||||
{
|
||||
get { return _top - 1; }
|
||||
get
|
||||
{
|
||||
int depth = _top - 1;
|
||||
if (IsStartToken(TokenType))
|
||||
return depth - 1;
|
||||
else
|
||||
return depth;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -148,6 +155,18 @@ namespace Newtonsoft.Json
|
||||
/// <returns></returns>
|
||||
public abstract bool Read();
|
||||
|
||||
public void Skip()
|
||||
{
|
||||
if (IsStartToken(TokenType))
|
||||
{
|
||||
int depth = Depth;
|
||||
|
||||
while (Read() && (depth < Depth))
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void SetToken(JsonToken newToken)
|
||||
{
|
||||
SetToken(newToken, null);
|
||||
@@ -185,6 +204,7 @@ namespace Newtonsoft.Json
|
||||
break;
|
||||
case JsonToken.PropertyName:
|
||||
_currentState = State.Property;
|
||||
Push(JsonTokenType.Property);
|
||||
break;
|
||||
case JsonToken.Undefined:
|
||||
case JsonToken.Integer:
|
||||
@@ -197,6 +217,10 @@ namespace Newtonsoft.Json
|
||||
break;
|
||||
}
|
||||
|
||||
JsonTokenType current = Peek();
|
||||
if (current == JsonTokenType.Property && _currentState == State.PostValue)
|
||||
Pop();
|
||||
|
||||
if (value != null)
|
||||
{
|
||||
_value = value;
|
||||
@@ -216,7 +240,7 @@ namespace Newtonsoft.Json
|
||||
if (GetTypeForCloseToken(endToken) != currentObject)
|
||||
throw new JsonReaderException(string.Format("JsonToken {0} is not valid for closing JsonType {1}.", endToken, currentObject));
|
||||
}
|
||||
|
||||
|
||||
protected void SetStateBasedOnCurrent()
|
||||
{
|
||||
JsonTokenType currentObject = Peek();
|
||||
@@ -240,6 +264,33 @@ namespace Newtonsoft.Json
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsStartToken(JsonToken token)
|
||||
{
|
||||
switch (token)
|
||||
{
|
||||
case JsonToken.StartObject:
|
||||
case JsonToken.StartArray:
|
||||
case JsonToken.StartConstructor:
|
||||
case JsonToken.PropertyName:
|
||||
return true;
|
||||
case JsonToken.None:
|
||||
case JsonToken.Comment:
|
||||
case JsonToken.Integer:
|
||||
case JsonToken.Float:
|
||||
case JsonToken.String:
|
||||
case JsonToken.Boolean:
|
||||
case JsonToken.Null:
|
||||
case JsonToken.Undefined:
|
||||
case JsonToken.EndObject:
|
||||
case JsonToken.EndArray:
|
||||
case JsonToken.EndConstructor:
|
||||
case JsonToken.Date:
|
||||
return false;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException("token", token, "Unexpected JsonToken value.");
|
||||
}
|
||||
}
|
||||
|
||||
private JsonTokenType GetTypeForCloseToken(JsonToken token)
|
||||
{
|
||||
switch (token)
|
||||
|
||||
@@ -34,6 +34,7 @@ using Newtonsoft.Json.Utilities;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace Newtonsoft.Json
|
||||
{
|
||||
@@ -45,6 +46,7 @@ namespace Newtonsoft.Json
|
||||
{
|
||||
private ReferenceLoopHandling _referenceLoopHandling;
|
||||
private MissingMemberHandling _missingMemberHandling;
|
||||
private ObjectCreationHandling _objectCreationHandling;
|
||||
private NullValueHandling _nullValueHandling;
|
||||
private int _level;
|
||||
private JsonConverterCollection _converters;
|
||||
@@ -95,6 +97,18 @@ namespace Newtonsoft.Json
|
||||
}
|
||||
}
|
||||
|
||||
public ObjectCreationHandling ObjectCreationHandling
|
||||
{
|
||||
get { return _objectCreationHandling; }
|
||||
set
|
||||
{
|
||||
if (value < ObjectCreationHandling.Auto || value > ObjectCreationHandling.Replace)
|
||||
throw new ArgumentOutOfRangeException("value");
|
||||
|
||||
_objectCreationHandling = value;
|
||||
}
|
||||
}
|
||||
|
||||
public JsonConverterCollection Converters
|
||||
{
|
||||
get
|
||||
@@ -113,6 +127,8 @@ namespace Newtonsoft.Json
|
||||
{
|
||||
_referenceLoopHandling = ReferenceLoopHandling.Error;
|
||||
_missingMemberHandling = MissingMemberHandling.Error;
|
||||
_nullValueHandling = NullValueHandling.Include;
|
||||
_objectCreationHandling = ObjectCreationHandling.Auto;
|
||||
}
|
||||
|
||||
#region Deserialize
|
||||
@@ -142,11 +158,16 @@ namespace Newtonsoft.Json
|
||||
return null;
|
||||
|
||||
if (objectType != null)
|
||||
return GetObject(reader, objectType);
|
||||
return CreateObject(reader, objectType, null);
|
||||
else
|
||||
return CreateJToken(reader);
|
||||
}
|
||||
|
||||
public object Deserialize(StringReader reader, Type objectType)
|
||||
{
|
||||
return Deserialize(new JsonTextReader(reader), objectType);
|
||||
}
|
||||
|
||||
private JToken CreateJToken(JsonReader reader)
|
||||
{
|
||||
JToken token;
|
||||
@@ -159,7 +180,7 @@ namespace Newtonsoft.Json
|
||||
return token;
|
||||
}
|
||||
|
||||
private object GetObject(JsonReader reader, Type objectType)
|
||||
private object CreateObject(JsonReader reader, Type objectType, object existingValue)
|
||||
{
|
||||
_level++;
|
||||
|
||||
@@ -177,10 +198,37 @@ namespace Newtonsoft.Json
|
||||
// populate a typed object or generic dictionary/array
|
||||
// depending upon whether an objectType was supplied
|
||||
case JsonToken.StartObject:
|
||||
value = (objectType != null) ? PopulateObject(reader, objectType) : CreateJToken(reader);
|
||||
if (objectType == null)
|
||||
{
|
||||
value = CreateJToken(reader);
|
||||
}
|
||||
else if (typeof(IDictionary).IsAssignableFrom(objectType) || ReflectionUtils.IsSubClass(objectType, typeof(IDictionary<,>)))
|
||||
{
|
||||
if (existingValue == null)
|
||||
value = CreateAndPopulateDictionary(reader, objectType);
|
||||
else
|
||||
value = PopulateDictionary(CollectionUtils.CreateDictionaryWrapper(existingValue), reader);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (existingValue == null)
|
||||
value = CreateAndPopulateObject(reader, objectType);
|
||||
else
|
||||
value = PopulateObject(existingValue, reader, objectType);
|
||||
}
|
||||
break;
|
||||
case JsonToken.StartArray:
|
||||
value = (objectType != null) ? PopulateList(reader, objectType) : CreateJToken(reader);
|
||||
if (objectType != null)
|
||||
{
|
||||
if (existingValue == null)
|
||||
value = CreateAndPopulateList(reader, objectType);
|
||||
else
|
||||
value = PopulateList(CollectionUtils.CreateListWrapper(existingValue), ReflectionUtils.GetListItemType(objectType), reader);
|
||||
}
|
||||
else
|
||||
{
|
||||
value = CreateJToken(reader);
|
||||
}
|
||||
break;
|
||||
case JsonToken.Integer:
|
||||
case JsonToken.Float:
|
||||
@@ -197,7 +245,10 @@ namespace Newtonsoft.Json
|
||||
break;
|
||||
case JsonToken.Null:
|
||||
case JsonToken.Undefined:
|
||||
value = null;
|
||||
if (objectType == typeof(DBNull))
|
||||
value = DBNull.Value;
|
||||
else
|
||||
value = null;
|
||||
break;
|
||||
default:
|
||||
throw new JsonSerializationException("Unexpected token while deserializing object: " + reader.TokenType);
|
||||
@@ -209,25 +260,6 @@ namespace Newtonsoft.Json
|
||||
return value;
|
||||
}
|
||||
|
||||
private DateTime CreateDate(JsonReader reader)
|
||||
{
|
||||
// move to parameter
|
||||
if (!reader.Read())
|
||||
throw new JsonSerializationException("Unexpected end while creating date.");
|
||||
|
||||
//TODO: add support for Date constructor with multiple arguments
|
||||
long ticks = Convert.ToInt64(reader.Value);
|
||||
DateTime date = JavaScriptConvert.ConvertJavaScriptTicksToDateTime(ticks);
|
||||
|
||||
// move to constructor end
|
||||
if (!reader.Read())
|
||||
throw new JsonSerializationException("Unexpected end while creating date.");
|
||||
if (reader.TokenType != JsonToken.EndConstructor)
|
||||
throw new JsonSerializationException("Unexpected token while creating date: " + reader.TokenType);
|
||||
|
||||
return date;
|
||||
}
|
||||
|
||||
private object EnsureType(object value, Type targetType)
|
||||
{
|
||||
// do something about null value when the targetType is a valuetype?
|
||||
@@ -329,32 +361,33 @@ namespace Newtonsoft.Json
|
||||
MemberMapping memberMapping = memberMappings[memberName];
|
||||
|
||||
if (memberMapping.Ignored)
|
||||
{
|
||||
reader.Skip();
|
||||
return;
|
||||
|
||||
// ignore member if it is readonly
|
||||
if (!memberMapping.Writable)
|
||||
return;
|
||||
}
|
||||
|
||||
// get the member's underlying type
|
||||
memberType = ReflectionUtils.GetMemberUnderlyingType(memberMapping.Member);
|
||||
object currentValue = ReflectionUtils.GetMemberValue(memberMapping.Member, target);
|
||||
|
||||
value = GetObject(reader, memberType);
|
||||
bool useExistingValue = (currentValue != null
|
||||
&& (_objectCreationHandling == ObjectCreationHandling.Auto || _objectCreationHandling == ObjectCreationHandling.Reuse)
|
||||
&& (reader.TokenType == JsonToken.StartArray || reader.TokenType == JsonToken.StartObject)
|
||||
&& (!memberType.IsArray && !ReflectionUtils.IsSubClass(memberType, typeof(ReadOnlyCollection<>))));
|
||||
|
||||
if (!memberMapping.Writable && !useExistingValue)
|
||||
{
|
||||
reader.Skip();
|
||||
return;
|
||||
}
|
||||
|
||||
value = CreateObject(reader, memberType, (useExistingValue) ? currentValue : null);
|
||||
|
||||
if (_nullValueHandling == NullValueHandling.Ignore && value == null)
|
||||
return;
|
||||
|
||||
ReflectionUtils.SetMemberValue(memberMapping.Member, target, value);
|
||||
}
|
||||
else if (typeof(IDictionary).IsAssignableFrom(targetType))
|
||||
{
|
||||
// attempt to get the IDictionary's type
|
||||
memberType = ReflectionUtils.GetDictionaryValueType(targetType);
|
||||
value = GetObject(reader, memberType);
|
||||
|
||||
Type keyType = ReflectionUtils.GetDictionaryKeyType(targetType);
|
||||
object keyValue = EnsureType(memberName, keyType);
|
||||
|
||||
((IDictionary)target).Add(keyValue, value);
|
||||
if (!useExistingValue)
|
||||
ReflectionUtils.SetMemberValue(memberMapping.Member, target, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -363,35 +396,67 @@ namespace Newtonsoft.Json
|
||||
}
|
||||
}
|
||||
|
||||
private object PopulateList(JsonReader reader, Type objectType)
|
||||
private object CreateAndPopulateDictionary(JsonReader reader, Type objectType)
|
||||
{
|
||||
Type elementType = ReflectionUtils.GetListItemType(objectType);
|
||||
IWrappedDictionary dictionary = CollectionUtils.CreateDictionaryWrapper(Activator.CreateInstance(objectType));
|
||||
PopulateDictionary(dictionary, reader);
|
||||
|
||||
IList populatedList = CollectionUtils.CreateAndPopulateList(objectType, delegate(IList list)
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
switch (reader.TokenType)
|
||||
{
|
||||
case JsonToken.EndArray:
|
||||
return;
|
||||
case JsonToken.Comment:
|
||||
break;
|
||||
default:
|
||||
object value = GetObject(reader, elementType);
|
||||
|
||||
list.Add(value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
throw new JsonSerializationException("Unexpected end when deserializing array.");
|
||||
});
|
||||
|
||||
return populatedList;
|
||||
return dictionary.UnderlyingDictionary;
|
||||
}
|
||||
|
||||
private object PopulateObject(JsonReader reader, Type objectType)
|
||||
private IDictionary PopulateDictionary(IWrappedDictionary dictionary, JsonReader reader)
|
||||
{
|
||||
Type dictionaryType = dictionary.UnderlyingDictionary.GetType();
|
||||
Type dictionaryKeyType = ReflectionUtils.GetDictionaryKeyType(dictionaryType);
|
||||
Type dictionaryValueType = ReflectionUtils.GetDictionaryValueType(dictionaryType);
|
||||
|
||||
while (reader.Read())
|
||||
{
|
||||
switch (reader.TokenType)
|
||||
{
|
||||
case JsonToken.PropertyName:
|
||||
object keyValue = EnsureType(reader.Value, dictionaryKeyType);
|
||||
reader.Read();
|
||||
|
||||
dictionary.Add(keyValue, CreateObject(reader, dictionaryValueType, null));
|
||||
break;
|
||||
case JsonToken.EndObject:
|
||||
return dictionary;
|
||||
default:
|
||||
throw new JsonSerializationException("Unexpected token when deserializing object: " + reader.TokenType);
|
||||
}
|
||||
}
|
||||
|
||||
throw new JsonSerializationException("Unexpected end when deserializing object.");
|
||||
}
|
||||
|
||||
private object CreateAndPopulateList(JsonReader reader, Type objectType)
|
||||
{
|
||||
return CollectionUtils.CreateAndPopulateList(objectType, l => PopulateList(l, ReflectionUtils.GetListItemType(objectType), reader));
|
||||
}
|
||||
|
||||
private IList PopulateList(IList list, Type listItemType, JsonReader reader)
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
switch (reader.TokenType)
|
||||
{
|
||||
case JsonToken.EndArray:
|
||||
return list;
|
||||
case JsonToken.Comment:
|
||||
break;
|
||||
default:
|
||||
object value = CreateObject(reader, listItemType, null);
|
||||
|
||||
list.Add(value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
throw new JsonSerializationException("Unexpected end when deserializing array.");
|
||||
}
|
||||
|
||||
private object CreateAndPopulateObject(JsonReader reader, Type objectType)
|
||||
{
|
||||
object newObject;
|
||||
|
||||
@@ -399,23 +464,8 @@ namespace Newtonsoft.Json
|
||||
{
|
||||
newObject = Activator.CreateInstance(objectType);
|
||||
|
||||
while (reader.Read())
|
||||
{
|
||||
switch (reader.TokenType)
|
||||
{
|
||||
case JsonToken.PropertyName:
|
||||
string memberName = reader.Value.ToString();
|
||||
|
||||
SetObjectMember(reader, newObject, objectType, memberName);
|
||||
break;
|
||||
case JsonToken.EndObject:
|
||||
return newObject;
|
||||
default:
|
||||
throw new JsonSerializationException("Unexpected token when deserializing object: " + reader.TokenType);
|
||||
}
|
||||
}
|
||||
|
||||
throw new JsonSerializationException("Unexpected end when deserializing object.");
|
||||
PopulateObject(newObject, reader, objectType);
|
||||
return newObject;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -442,15 +492,9 @@ namespace Newtonsoft.Json
|
||||
if (!reader.Read())
|
||||
throw new JsonSerializationException(string.Format("Unexpected end when setting {0}'s value.", memberName));
|
||||
|
||||
|
||||
if (matchingConstructorParameter != null)
|
||||
{
|
||||
constructorParameters[matchingConstructorParameter] = GetObject(reader, matchingConstructorParameter.ParameterType);
|
||||
}
|
||||
constructorParameters[matchingConstructorParameter] = CreateObject(reader, matchingConstructorParameter.ParameterType, null);
|
||||
|
||||
|
||||
|
||||
//SetObjectMember(reader, newObject, objectType, memberName);
|
||||
break;
|
||||
case JsonToken.EndObject:
|
||||
exit = true;
|
||||
@@ -465,6 +509,27 @@ namespace Newtonsoft.Json
|
||||
return newObject;
|
||||
}
|
||||
}
|
||||
|
||||
private object PopulateObject(object newObject, JsonReader reader, Type objectType)
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
switch (reader.TokenType)
|
||||
{
|
||||
case JsonToken.PropertyName:
|
||||
string memberName = reader.Value.ToString();
|
||||
|
||||
SetObjectMember(reader, newObject, objectType, memberName);
|
||||
break;
|
||||
case JsonToken.EndObject:
|
||||
return newObject;
|
||||
default:
|
||||
throw new JsonSerializationException("Unexpected token when deserializing object: " + reader.TokenType);
|
||||
}
|
||||
}
|
||||
|
||||
throw new JsonSerializationException("Unexpected end when deserializing object.");
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Serialize
|
||||
@@ -560,6 +625,9 @@ namespace Newtonsoft.Json
|
||||
case TypeCode.Decimal:
|
||||
writer.WriteValue((decimal)convertible);
|
||||
break;
|
||||
case TypeCode.DBNull:
|
||||
writer.WriteNull();
|
||||
break;
|
||||
default:
|
||||
SerializeObject(writer, value);
|
||||
break;
|
||||
@@ -691,10 +759,7 @@ namespace Newtonsoft.Json
|
||||
|
||||
private void SerializeCollection(JsonWriter writer, ICollection values)
|
||||
{
|
||||
object[] collectionValues = new object[values.Count];
|
||||
values.CopyTo(collectionValues, 0);
|
||||
|
||||
SerializeList(writer, collectionValues);
|
||||
SerializeList(writer, values.Cast<object>().ToList());
|
||||
}
|
||||
|
||||
private void SerializeList(JsonWriter writer, IList values)
|
||||
|
||||
@@ -789,7 +789,7 @@ namespace Newtonsoft.Json
|
||||
/// <summary>
|
||||
/// Changes the <see cref="State"/> to Closed.
|
||||
/// </summary>
|
||||
public void Close()
|
||||
public override void Close()
|
||||
{
|
||||
base.Close();
|
||||
|
||||
|
||||
@@ -295,7 +295,7 @@ namespace Newtonsoft.Json
|
||||
ValidationUtils.ArgumentNotNull(reader, "reader");
|
||||
|
||||
int currentDepth = (reader.TokenType == JsonToken.None) ? -1 : reader.Depth;
|
||||
bool continue1;
|
||||
|
||||
do
|
||||
{
|
||||
switch (reader.TokenType)
|
||||
|
||||
@@ -73,6 +73,7 @@
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="ObjectCreationHandling.cs" />
|
||||
<Compile Include="Converters\IsoDateTimeConverter.cs" />
|
||||
<Compile Include="Converters\JavaScriptDateTimeConverter.cs" />
|
||||
<Compile Include="Converters\JsonDateTimeSerializationMode.cs" />
|
||||
@@ -109,6 +110,7 @@
|
||||
<Compile Include="NullValueHandling.cs" />
|
||||
<Compile Include="ReferenceLoopHandling.cs" />
|
||||
<Compile Include="Utilities\DateTimeUtils.cs" />
|
||||
<Compile Include="Utilities\DictionaryWrapper.cs" />
|
||||
<Compile Include="Utilities\JavaScriptUtils.cs" />
|
||||
<Compile Include="JsonToken.cs" />
|
||||
<Compile Include="JsonWriter.cs" />
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
#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;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Newtonsoft.Json
|
||||
{
|
||||
public enum ObjectCreationHandling
|
||||
{
|
||||
Auto = 0,
|
||||
Reuse = 1,
|
||||
Replace = 2
|
||||
}
|
||||
}
|
||||
@@ -191,7 +191,7 @@ namespace Newtonsoft.Json.Utilities
|
||||
/// </summary>
|
||||
/// <param name="initial">The list to add to.</param>
|
||||
/// <param name="collection">The collection of elements to add.</param>
|
||||
public static void AddRange<T>(IList<T> initial, IEnumerable<T> collection)
|
||||
public static void AddRange<T>(this IList<T> initial, IEnumerable<T> collection)
|
||||
{
|
||||
if (initial == null)
|
||||
throw new ArgumentNullException("initial");
|
||||
@@ -205,6 +205,14 @@ namespace Newtonsoft.Json.Utilities
|
||||
}
|
||||
}
|
||||
|
||||
public static void AddRange(this IList initial, IEnumerable collection)
|
||||
{
|
||||
ValidationUtils.ArgumentNotNull(initial, "initial");
|
||||
|
||||
ListWrapper<object> wrapper = new ListWrapper<object>(initial);
|
||||
wrapper.AddRange(collection.Cast<object>());
|
||||
}
|
||||
|
||||
public static List<T> Distinct<T>(List<T> collection)
|
||||
{
|
||||
List<T> distinctList = new List<T>();
|
||||
@@ -336,11 +344,11 @@ namespace Newtonsoft.Json.Utilities
|
||||
return tempList.ToArray();
|
||||
}
|
||||
|
||||
public static object CreateGenericList(Type listType)
|
||||
public static IList CreateGenericList(Type listType)
|
||||
{
|
||||
ValidationUtils.ArgumentNotNull(listType, "listType");
|
||||
|
||||
return ReflectionUtils.CreateGeneric(typeof(List<>), listType);
|
||||
return (IList)ReflectionUtils.CreateGeneric(typeof(List<>), listType);
|
||||
}
|
||||
|
||||
public static bool IsListType(Type type)
|
||||
@@ -357,13 +365,70 @@ namespace Newtonsoft.Json.Utilities
|
||||
return false;
|
||||
}
|
||||
|
||||
public static IWrappedList CreateListWrapper(object list)
|
||||
{
|
||||
ValidationUtils.ArgumentNotNull(list, "list");
|
||||
|
||||
Type listDefinition;
|
||||
if (ReflectionUtils.IsSubClass(list.GetType(), typeof(IList<>), out listDefinition))
|
||||
{
|
||||
Type listItemType = ReflectionUtils.GetListItemType(listDefinition);
|
||||
|
||||
// Activator.CreateInstance throws AmbiguousMatchException. Manually invoke constructor
|
||||
Func<Type, IList<object>, object> instanceCreator = (t, a) =>
|
||||
{
|
||||
ConstructorInfo c = t.GetConstructor(new[] {listDefinition});
|
||||
return c.Invoke(new[] { list });
|
||||
};
|
||||
|
||||
return (IWrappedList)ReflectionUtils.CreateGeneric(typeof(ListWrapper<>), new[] { listItemType }, instanceCreator, list);
|
||||
}
|
||||
else if (list is IList)
|
||||
{
|
||||
return new ListWrapper<object>((IList)list);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception(string.Format("Can not create ListWrapper for type {0}.", list.GetType()));
|
||||
}
|
||||
}
|
||||
|
||||
public static IWrappedDictionary CreateDictionaryWrapper(object dictionary)
|
||||
{
|
||||
ValidationUtils.ArgumentNotNull(dictionary, "dictionary");
|
||||
|
||||
Type dictionaryDefinition;
|
||||
if (ReflectionUtils.IsSubClass(dictionary.GetType(), typeof(IDictionary<,>), out dictionaryDefinition))
|
||||
{
|
||||
Type dictionaryKeyType = ReflectionUtils.GetDictionaryKeyType(dictionaryDefinition);
|
||||
Type dictionaryValueType = ReflectionUtils.GetDictionaryValueType(dictionaryDefinition);
|
||||
|
||||
// Activator.CreateInstance throws AmbiguousMatchException. Manually invoke constructor
|
||||
Func<Type, IList<object>, object> instanceCreator = (t, a) =>
|
||||
{
|
||||
ConstructorInfo c = t.GetConstructor(new[] { dictionaryDefinition });
|
||||
return c.Invoke(new[] { dictionary });
|
||||
};
|
||||
|
||||
return (IWrappedDictionary)ReflectionUtils.CreateGeneric(typeof(DictionaryWrapper<,>), new[] { dictionaryKeyType, dictionaryValueType }, instanceCreator, dictionary);
|
||||
}
|
||||
else if (dictionary is IDictionary)
|
||||
{
|
||||
return new DictionaryWrapper<object, object>((IDictionary)dictionary);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception(string.Format("Can not create DictionaryWrapper for type {0}.", dictionary.GetType()));
|
||||
}
|
||||
}
|
||||
|
||||
public static IList CreateAndPopulateList(Type listType, Action<IList> populateList)
|
||||
{
|
||||
ValidationUtils.ArgumentNotNull(listType, "listType");
|
||||
ValidationUtils.ArgumentNotNull(populateList, "populateList");
|
||||
|
||||
IList list;
|
||||
Type readOnlyCollectionType;
|
||||
Type collectionType;
|
||||
bool isReadOnlyOrFixedSize = false;
|
||||
|
||||
if (listType.IsArray)
|
||||
@@ -373,9 +438,9 @@ namespace Newtonsoft.Json.Utilities
|
||||
list = new ArrayList();
|
||||
isReadOnlyOrFixedSize = true;
|
||||
}
|
||||
else if (ReflectionUtils.IsSubClass(listType, typeof(ReadOnlyCollection<>), out readOnlyCollectionType))
|
||||
else if (ReflectionUtils.IsSubClass(listType, typeof(ReadOnlyCollection<>), out collectionType))
|
||||
{
|
||||
Type readOnlyCollectionContentsType = readOnlyCollectionType.GetGenericArguments()[0];
|
||||
Type readOnlyCollectionContentsType = collectionType.GetGenericArguments()[0];
|
||||
Type genericEnumerable = ReflectionUtils.MakeGenericType(typeof(IEnumerable<>), readOnlyCollectionContentsType);
|
||||
bool suitableConstructor = false;
|
||||
|
||||
@@ -394,22 +459,34 @@ namespace Newtonsoft.Json.Utilities
|
||||
}
|
||||
|
||||
if (!suitableConstructor)
|
||||
throw new Exception(string.Format("Readonly type {0} does not have a public constructor that takes a type that implements {1}.", listType, genericEnumerable));
|
||||
throw new Exception(string.Format("Read-only type {0} does not have a public constructor that takes a type that implements {1}.", listType, genericEnumerable));
|
||||
|
||||
// can't add or modify a readonly list
|
||||
// use List<T> and convert once populated
|
||||
list = (IList)CreateGenericList(readOnlyCollectionContentsType);
|
||||
isReadOnlyOrFixedSize = true;
|
||||
}
|
||||
else if (typeof(IList).IsAssignableFrom(listType) && ReflectionUtils.IsInstantiatableType(listType))
|
||||
else if (typeof(IList).IsAssignableFrom(listType))
|
||||
{
|
||||
list = (IList)Activator.CreateInstance(listType);
|
||||
if (ReflectionUtils.IsInstantiatableType(listType))
|
||||
list = (IList)Activator.CreateInstance(listType);
|
||||
else if (listType == typeof(IList))
|
||||
list = new List<object>();
|
||||
else
|
||||
list = null;
|
||||
}
|
||||
else if (listType.IsGenericType && listType.GetGenericTypeDefinition() == typeof(IList<>))
|
||||
{
|
||||
list = CollectionUtils.CreateGenericList(ReflectionUtils.GetListItemType(listType));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception(string.Format("Cannot create and populate list type {0}.", listType));
|
||||
list = null;
|
||||
}
|
||||
|
||||
if (list == null)
|
||||
throw new Exception(string.Format("Cannot create and populate list type {0}.", listType));
|
||||
|
||||
populateList(list);
|
||||
|
||||
// create readonly and fixed sized collections using the temporary list
|
||||
|
||||
@@ -0,0 +1,400 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Collections;
|
||||
using System.Threading;
|
||||
|
||||
namespace Newtonsoft.Json.Utilities
|
||||
{
|
||||
public interface IWrappedDictionary : IDictionary
|
||||
{
|
||||
object UnderlyingDictionary { get; }
|
||||
}
|
||||
|
||||
public class DictionaryWrapper<TKey, TValue> : IDictionary<TKey, TValue>, IWrappedDictionary
|
||||
{
|
||||
private readonly IDictionary _dictionary;
|
||||
private readonly IDictionary<TKey, TValue> _genericDictionary;
|
||||
private object _syncRoot;
|
||||
|
||||
public DictionaryWrapper(IDictionary dictionary)
|
||||
{
|
||||
ValidationUtils.ArgumentNotNull(dictionary, "dictionary");
|
||||
|
||||
_dictionary = dictionary;
|
||||
}
|
||||
|
||||
public DictionaryWrapper(IDictionary<TKey, TValue> dictionary)
|
||||
{
|
||||
ValidationUtils.ArgumentNotNull(dictionary, "dictionary");
|
||||
|
||||
_genericDictionary = dictionary;
|
||||
}
|
||||
|
||||
public void Add(TKey key, TValue value)
|
||||
{
|
||||
if (_genericDictionary != null)
|
||||
_genericDictionary.Add(key, value);
|
||||
else
|
||||
_dictionary.Add(key, value);
|
||||
}
|
||||
|
||||
public bool ContainsKey(TKey key)
|
||||
{
|
||||
if (_genericDictionary != null)
|
||||
return _genericDictionary.ContainsKey(key);
|
||||
else
|
||||
return _dictionary.Contains(key);
|
||||
}
|
||||
|
||||
public ICollection<TKey> Keys
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_genericDictionary != null)
|
||||
return _genericDictionary.Keys;
|
||||
else
|
||||
return _dictionary.Keys.Cast<TKey>().ToList();
|
||||
}
|
||||
}
|
||||
|
||||
public bool Remove(TKey key)
|
||||
{
|
||||
if (_genericDictionary != null)
|
||||
{
|
||||
return _genericDictionary.Remove(key);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_dictionary.Contains(key))
|
||||
{
|
||||
_dictionary.Remove(key);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool TryGetValue(TKey key, out TValue value)
|
||||
{
|
||||
if (_genericDictionary != null)
|
||||
{
|
||||
return _genericDictionary.TryGetValue(key, out value);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!_dictionary.Contains(key))
|
||||
{
|
||||
value = default(TValue);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
value = (TValue)_dictionary[key];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ICollection<TValue> Values
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_genericDictionary != null)
|
||||
return _genericDictionary.Values;
|
||||
else
|
||||
return _dictionary.Values.Cast<TValue>().ToList();
|
||||
}
|
||||
}
|
||||
|
||||
public TValue this[TKey key]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_genericDictionary != null)
|
||||
return _genericDictionary[key];
|
||||
else
|
||||
return (TValue)_dictionary[key];
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_genericDictionary != null)
|
||||
_genericDictionary[key] = value;
|
||||
else
|
||||
_dictionary[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
public void Add(KeyValuePair<TKey, TValue> item)
|
||||
{
|
||||
if (_genericDictionary != null)
|
||||
_genericDictionary.Add(item);
|
||||
else
|
||||
((IList)_dictionary).Add(item);
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
if (_genericDictionary != null)
|
||||
_genericDictionary.Clear();
|
||||
else
|
||||
_dictionary.Clear();
|
||||
}
|
||||
|
||||
public bool Contains(KeyValuePair<TKey, TValue> item)
|
||||
{
|
||||
if (_genericDictionary != null)
|
||||
return _genericDictionary.Contains(item);
|
||||
else
|
||||
return ((IList)_dictionary).Contains(item);
|
||||
}
|
||||
|
||||
public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
|
||||
{
|
||||
if (_genericDictionary != null)
|
||||
{
|
||||
_genericDictionary.CopyTo(array, arrayIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (DictionaryEntry item in _dictionary)
|
||||
{
|
||||
array[arrayIndex++] = new KeyValuePair<TKey, TValue>((TKey)item.Key, (TValue)item.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_genericDictionary != null)
|
||||
return _genericDictionary.Count;
|
||||
else
|
||||
return _dictionary.Count;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsReadOnly
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_genericDictionary != null)
|
||||
return _genericDictionary.IsReadOnly;
|
||||
else
|
||||
return _dictionary.IsReadOnly;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Remove(KeyValuePair<TKey, TValue> item)
|
||||
{
|
||||
if (_genericDictionary != null)
|
||||
{
|
||||
return _genericDictionary.Remove(item);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_dictionary.Contains(item.Key))
|
||||
{
|
||||
object value = _dictionary[item.Key];
|
||||
|
||||
if (object.Equals(value, item.Value))
|
||||
{
|
||||
_dictionary.Remove(item.Key);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
|
||||
{
|
||||
if (_genericDictionary != null)
|
||||
return _genericDictionary.GetEnumerator();
|
||||
else
|
||||
return _dictionary.Cast<DictionaryEntry>().Select(de => new KeyValuePair<TKey, TValue>((TKey)de.Key, (TValue)de.Value)).GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
void IDictionary.Add(object key, object value)
|
||||
{
|
||||
if (_genericDictionary != null)
|
||||
_genericDictionary.Add((TKey)key, (TValue)value);
|
||||
else
|
||||
_dictionary.Add(key, value);
|
||||
}
|
||||
|
||||
bool IDictionary.Contains(object key)
|
||||
{
|
||||
if (_genericDictionary != null)
|
||||
return _genericDictionary.ContainsKey((TKey)key);
|
||||
else
|
||||
return _dictionary.Contains(key);
|
||||
}
|
||||
|
||||
private struct DictionaryEnumerator : IDictionaryEnumerator
|
||||
{
|
||||
private IEnumerator _e;
|
||||
|
||||
public DictionaryEnumerator(IEnumerator e)
|
||||
{
|
||||
ValidationUtils.ArgumentNotNull(e, "e");
|
||||
_e = e;
|
||||
}
|
||||
|
||||
public DictionaryEntry Entry
|
||||
{
|
||||
get { return (DictionaryEntry)Current; }
|
||||
}
|
||||
|
||||
public object Key
|
||||
{
|
||||
get { return Entry.Key; }
|
||||
}
|
||||
|
||||
public object Value
|
||||
{
|
||||
get { return Entry.Value; }
|
||||
}
|
||||
|
||||
public object Current
|
||||
{
|
||||
get { return _e.Current; }
|
||||
}
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
return _e.MoveNext();
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
_e.Reset();
|
||||
}
|
||||
}
|
||||
|
||||
IDictionaryEnumerator IDictionary.GetEnumerator()
|
||||
{
|
||||
if (_genericDictionary != null)
|
||||
return new DictionaryEnumerator(_genericDictionary.GetEnumerator());
|
||||
else
|
||||
return _dictionary.GetEnumerator();
|
||||
}
|
||||
|
||||
bool IDictionary.IsFixedSize
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_genericDictionary != null)
|
||||
return false;
|
||||
else
|
||||
return _dictionary.IsFixedSize;
|
||||
}
|
||||
}
|
||||
|
||||
ICollection IDictionary.Keys
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_genericDictionary != null)
|
||||
return _genericDictionary.Keys.ToList();
|
||||
else
|
||||
return _dictionary.Keys;
|
||||
}
|
||||
}
|
||||
|
||||
public void Remove(object key)
|
||||
{
|
||||
if (_genericDictionary != null)
|
||||
_genericDictionary.Remove((TKey)key);
|
||||
else
|
||||
_dictionary.Remove(key);
|
||||
}
|
||||
|
||||
ICollection IDictionary.Values
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_genericDictionary != null)
|
||||
return _genericDictionary.Values.ToList();
|
||||
else
|
||||
return _dictionary.Values;
|
||||
}
|
||||
}
|
||||
|
||||
object IDictionary.this[object key]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_genericDictionary != null)
|
||||
return _genericDictionary[(TKey)key];
|
||||
else
|
||||
return _dictionary[key];
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_genericDictionary != null)
|
||||
_genericDictionary[(TKey)key] = (TValue)value;
|
||||
else
|
||||
_dictionary[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
void ICollection.CopyTo(Array array, int index)
|
||||
{
|
||||
if (_genericDictionary != null)
|
||||
_genericDictionary.CopyTo((KeyValuePair<TKey, TValue>[])array, index);
|
||||
else
|
||||
_dictionary.CopyTo(array, index);
|
||||
}
|
||||
|
||||
bool ICollection.IsSynchronized
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_genericDictionary != null)
|
||||
return false;
|
||||
else
|
||||
return _dictionary.IsSynchronized;
|
||||
}
|
||||
}
|
||||
|
||||
object ICollection.SyncRoot
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_syncRoot == null)
|
||||
Interlocked.CompareExchange(ref _syncRoot, new object(), null);
|
||||
|
||||
return _syncRoot;
|
||||
}
|
||||
}
|
||||
|
||||
public object UnderlyingDictionary
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_genericDictionary != null)
|
||||
return _genericDictionary;
|
||||
else
|
||||
return _dictionary;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,11 +7,7 @@ using System.Text;
|
||||
|
||||
namespace Newtonsoft.Json.Utilities
|
||||
{
|
||||
internal delegate void Action();
|
||||
internal delegate T Creator<T>();
|
||||
internal delegate T Func<A0, T>(A0 arg0);
|
||||
internal delegate T Func<A0, A1, T>(A0 arg0, A1 arg1);
|
||||
internal delegate T Func<A0, A1, A2, T>(A0 arg0, A1 arg1, A2 arg2);
|
||||
|
||||
internal static class MiscellaneousUtils
|
||||
{
|
||||
|
||||
@@ -29,6 +29,7 @@ using System.Text;
|
||||
using System.Reflection;
|
||||
using System.Collections;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
|
||||
namespace Newtonsoft.Json.Utilities
|
||||
{
|
||||
@@ -536,13 +537,19 @@ namespace Newtonsoft.Json.Utilities
|
||||
}
|
||||
|
||||
public static object CreateGeneric(Type genericTypeDefinition, IList<Type> innerTypes, params object[] args)
|
||||
{
|
||||
return CreateGeneric(genericTypeDefinition, innerTypes, (t, a) => Activator.CreateInstance(t, a.ToArray()), args);
|
||||
}
|
||||
|
||||
public static object CreateGeneric(Type genericTypeDefinition, IList<Type> innerTypes, Func<Type, IList<object>, object> instanceCreator, params object[] args)
|
||||
{
|
||||
ValidationUtils.ArgumentNotNull(genericTypeDefinition, "genericTypeDefinition");
|
||||
ValidationUtils.ArgumentNotNullOrEmpty(innerTypes, "innerTypes");
|
||||
ValidationUtils.ArgumentNotNull(instanceCreator, "createInstance");
|
||||
|
||||
Type specificType = MakeGenericType(genericTypeDefinition, CollectionUtils.CreateArray(innerTypes));
|
||||
|
||||
return Activator.CreateInstance(specificType, args);
|
||||
return instanceCreator(specificType, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user