-Changed serializer to better work with ICollection<T> when deserializing

-Improved serializer caching of static type data
This commit is contained in:
JamesNK
2008-09-08 08:46:23 +00:00
parent 7b0f3a7ccc
commit d193ae37be
11 changed files with 896 additions and 25 deletions
+242
View File
@@ -0,0 +1,242 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:2.0.50727.3053
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
[assembly: global::System.Data.Objects.DataClasses.EdmSchemaAttribute()]
[assembly: global::System.Data.Objects.DataClasses.EdmRelationshipAttribute("EntityDataModel", "PurchasePurchaseLine", "Purchase", global::System.Data.Metadata.Edm.RelationshipMultiplicity.One, typeof(Newtonsoft.Json.Tests.Purchase), "PurchaseLine", global::System.Data.Metadata.Edm.RelationshipMultiplicity.Many, typeof(Newtonsoft.Json.Tests.PurchaseLine))]
// Original file name:
// Generation date: 7/09/2008 7:58:08 p.m.
namespace Newtonsoft.Json.Tests
{
/// <summary>
/// There are no comments for EntityDataModelContainer in the schema.
/// </summary>
public partial class EntityDataModelContainer : global::System.Data.Objects.ObjectContext
{
/// <summary>
/// Initializes a new EntityDataModelContainer object using the connection string found in the 'EntityDataModelContainer' section of the application configuration file.
/// </summary>
public EntityDataModelContainer() :
base("name=EntityDataModelContainer", "EntityDataModelContainer")
{
this.OnContextCreated();
}
/// <summary>
/// Initialize a new EntityDataModelContainer object.
/// </summary>
public EntityDataModelContainer(string connectionString) :
base(connectionString, "EntityDataModelContainer")
{
this.OnContextCreated();
}
/// <summary>
/// Initialize a new EntityDataModelContainer object.
/// </summary>
public EntityDataModelContainer(global::System.Data.EntityClient.EntityConnection connection) :
base(connection, "EntityDataModelContainer")
{
this.OnContextCreated();
}
partial void OnContextCreated();
/// <summary>
/// There are no comments for PurchaseSet in the schema.
/// </summary>
public global::System.Data.Objects.ObjectQuery<Purchase> PurchaseSet
{
get
{
if ((this._PurchaseSet == null))
{
this._PurchaseSet = base.CreateQuery<Purchase>("[PurchaseSet]");
}
return this._PurchaseSet;
}
}
private global::System.Data.Objects.ObjectQuery<Purchase> _PurchaseSet;
/// <summary>
/// There are no comments for PurchaseLineSet in the schema.
/// </summary>
public global::System.Data.Objects.ObjectQuery<PurchaseLine> PurchaseLineSet
{
get
{
if ((this._PurchaseLineSet == null))
{
this._PurchaseLineSet = base.CreateQuery<PurchaseLine>("[PurchaseLineSet]");
}
return this._PurchaseLineSet;
}
}
private global::System.Data.Objects.ObjectQuery<PurchaseLine> _PurchaseLineSet;
/// <summary>
/// There are no comments for PurchaseSet in the schema.
/// </summary>
public void AddToPurchaseSet(Purchase purchase)
{
base.AddObject("PurchaseSet", purchase);
}
/// <summary>
/// There are no comments for PurchaseLineSet in the schema.
/// </summary>
public void AddToPurchaseLineSet(PurchaseLine purchaseLine)
{
base.AddObject("PurchaseLineSet", purchaseLine);
}
}
/// <summary>
/// There are no comments for EntityDataModel.Purchase in the schema.
/// </summary>
/// <KeyProperties>
/// Id
/// </KeyProperties>
[global::System.Data.Objects.DataClasses.EdmEntityTypeAttribute(NamespaceName="EntityDataModel", Name="Purchase")]
[global::System.Runtime.Serialization.DataContractAttribute(IsReference=true)]
[global::System.Serializable()]
public partial class Purchase : global::System.Data.Objects.DataClasses.EntityObject
{
/// <summary>
/// Create a new Purchase object.
/// </summary>
/// <param name="id">Initial value of Id.</param>
public static Purchase CreatePurchase(int id)
{
Purchase purchase = new Purchase();
purchase.Id = id;
return purchase;
}
/// <summary>
/// There are no comments for Property Id in the schema.
/// </summary>
[global::System.Data.Objects.DataClasses.EdmScalarPropertyAttribute(EntityKeyProperty=true, IsNullable=false)]
[global::System.Runtime.Serialization.DataMemberAttribute()]
public int Id
{
get
{
return this._Id;
}
set
{
this.OnIdChanging(value);
this.ReportPropertyChanging("Id");
this._Id = global::System.Data.Objects.DataClasses.StructuralObject.SetValidValue(value);
this.ReportPropertyChanged("Id");
this.OnIdChanged();
}
}
private int _Id;
partial void OnIdChanging(int value);
partial void OnIdChanged();
/// <summary>
/// There are no comments for PurchaseLine in the schema.
/// </summary>
[global::System.Data.Objects.DataClasses.EdmRelationshipNavigationPropertyAttribute("EntityDataModel", "PurchasePurchaseLine", "PurchaseLine")]
[global::System.Xml.Serialization.XmlIgnoreAttribute()]
[global::System.Xml.Serialization.SoapIgnoreAttribute()]
[global::System.Runtime.Serialization.DataMemberAttribute()]
public global::System.Data.Objects.DataClasses.EntityCollection<PurchaseLine> PurchaseLine
{
get
{
return ((global::System.Data.Objects.DataClasses.IEntityWithRelationships)(this)).RelationshipManager.GetRelatedCollection<PurchaseLine>("EntityDataModel.PurchasePurchaseLine", "PurchaseLine");
}
set
{
if ((value != null))
{
((global::System.Data.Objects.DataClasses.IEntityWithRelationships)(this)).RelationshipManager.InitializeRelatedCollection<PurchaseLine>("EntityDataModel.PurchasePurchaseLine", "PurchaseLine", value);
}
}
}
}
/// <summary>
/// There are no comments for EntityDataModel.PurchaseLine in the schema.
/// </summary>
/// <KeyProperties>
/// Id
/// </KeyProperties>
[global::System.Data.Objects.DataClasses.EdmEntityTypeAttribute(NamespaceName="EntityDataModel", Name="PurchaseLine")]
[global::System.Runtime.Serialization.DataContractAttribute(IsReference=true)]
[global::System.Serializable()]
public partial class PurchaseLine : global::System.Data.Objects.DataClasses.EntityObject
{
/// <summary>
/// Create a new PurchaseLine object.
/// </summary>
/// <param name="id">Initial value of Id.</param>
public static PurchaseLine CreatePurchaseLine(int id)
{
PurchaseLine purchaseLine = new PurchaseLine();
purchaseLine.Id = id;
return purchaseLine;
}
/// <summary>
/// There are no comments for Property Id in the schema.
/// </summary>
[global::System.Data.Objects.DataClasses.EdmScalarPropertyAttribute(EntityKeyProperty=true, IsNullable=false)]
[global::System.Runtime.Serialization.DataMemberAttribute()]
public int Id
{
get
{
return this._Id;
}
set
{
this.OnIdChanging(value);
this.ReportPropertyChanging("Id");
this._Id = global::System.Data.Objects.DataClasses.StructuralObject.SetValidValue(value);
this.ReportPropertyChanged("Id");
this.OnIdChanged();
}
}
private int _Id;
partial void OnIdChanging(int value);
partial void OnIdChanged();
/// <summary>
/// There are no comments for Purchase in the schema.
/// </summary>
[global::System.Data.Objects.DataClasses.EdmRelationshipNavigationPropertyAttribute("EntityDataModel", "PurchasePurchaseLine", "Purchase")]
[global::System.Xml.Serialization.XmlIgnoreAttribute()]
[global::System.Xml.Serialization.SoapIgnoreAttribute()]
[global::System.Runtime.Serialization.DataMemberAttribute()]
public Purchase Purchase
{
get
{
return ((global::System.Data.Objects.DataClasses.IEntityWithRelationships)(this)).RelationshipManager.GetRelatedReference<Purchase>("EntityDataModel.PurchasePurchaseLine", "Purchase").Value;
}
set
{
((global::System.Data.Objects.DataClasses.IEntityWithRelationships)(this)).RelationshipManager.GetRelatedReference<Purchase>("EntityDataModel.PurchasePurchaseLine", "Purchase").Value = value;
}
}
/// <summary>
/// There are no comments for Purchase in the schema.
/// </summary>
[global::System.ComponentModel.BrowsableAttribute(false)]
[global::System.Runtime.Serialization.DataMemberAttribute()]
public global::System.Data.Objects.DataClasses.EntityReference<Purchase> PurchaseReference
{
get
{
return ((global::System.Data.Objects.DataClasses.IEntityWithRelationships)(this)).RelationshipManager.GetRelatedReference<Purchase>("EntityDataModel.PurchasePurchaseLine", "Purchase");
}
set
{
if ((value != null))
{
((global::System.Data.Objects.DataClasses.IEntityWithRelationships)(this)).RelationshipManager.InitializeRelatedReference<Purchase>("EntityDataModel.PurchasePurchaseLine", "Purchase", value);
}
}
}
}
}
@@ -0,0 +1,67 @@
<?xml version="1.0" encoding="utf-8"?>
<edmx:Edmx Version="1.0" xmlns:edmx="http://schemas.microsoft.com/ado/2007/06/edmx">
<!-- EF Runtime content -->
<edmx:Runtime>
<!-- SSDL content -->
<edmx:StorageModels>
<Schema xmlns="http://schemas.microsoft.com/ado/2006/04/edm/ssdl" Namespace="EntityDataModel.Target" Alias="Self" Provider="System.Data.SqlClient" ProviderManifestToken="2005">
<EntityContainer Name="EntityDataModelTargetContainer" >
</EntityContainer>
</Schema>
</edmx:StorageModels>
<!-- CSDL content -->
<edmx:ConceptualModels>
<Schema xmlns="http://schemas.microsoft.com/ado/2006/04/edm" Namespace="EntityDataModel" Alias="Self">
<EntityContainer Name="EntityDataModelContainer" >
<EntitySet Name="PurchaseSet" EntityType="EntityDataModel.Purchase" />
<EntitySet Name="PurchaseLineSet" EntityType="EntityDataModel.PurchaseLine" />
<AssociationSet Name="PurchasePurchaseLine" Association="EntityDataModel.PurchasePurchaseLine">
<End Role="Purchase" EntitySet="PurchaseSet" />
<End Role="PurchaseLine" EntitySet="PurchaseLineSet" /></AssociationSet></EntityContainer>
<EntityType Name="Purchase">
<Key>
<PropertyRef Name="Id" /></Key>
<Property Name="Id" Type="Int32" Nullable="false" />
<NavigationProperty Name="PurchaseLine" Relationship="EntityDataModel.PurchasePurchaseLine" FromRole="Purchase" ToRole="PurchaseLine" /></EntityType>
<EntityType Name="PurchaseLine">
<Key>
<PropertyRef Name="Id" /></Key>
<Property Name="Id" Type="Int32" Nullable="false" />
<NavigationProperty Name="Purchase" Relationship="EntityDataModel.PurchasePurchaseLine" FromRole="PurchaseLine" ToRole="Purchase" /></EntityType>
<Association Name="PurchasePurchaseLine">
<End Type="EntityDataModel.Purchase" Role="Purchase" Multiplicity="1" />
<End Type="EntityDataModel.PurchaseLine" Role="PurchaseLine" Multiplicity="*" /></Association></Schema>
</edmx:ConceptualModels>
<!-- C-S mapping content -->
<edmx:Mappings>
<Mapping xmlns="urn:schemas-microsoft-com:windows:storage:mapping:CS" Space="C-S">
<Alias Key="Model" Value="EntityDataModel" />
<Alias Key="Target" Value="EntityDataModel.Target" />
<EntityContainerMapping CdmEntityContainer="EntityDataModelContainer" StorageEntityContainer="EntityDataModelTargetContainer">
</EntityContainerMapping>
</Mapping>
</edmx:Mappings>
</edmx:Runtime>
<!-- EF Designer content (DO NOT EDIT MANUALLY BELOW HERE) -->
<edmx:Designer xmlns="http://schemas.microsoft.com/ado/2007/06/edmx">
<edmx:Connection>
<DesignerInfoPropertySet>
<DesignerProperty Name="MetadataArtifactProcessing" Value="EmbedInOutputAssembly" />
</DesignerInfoPropertySet>
</edmx:Connection>
<edmx:Options>
<DesignerInfoPropertySet>
<DesignerProperty Name="ValidateOnBuild" Value="true" />
</DesignerInfoPropertySet>
</edmx:Options>
<!-- Diagram content (shape and connector positions) -->
<edmx:Diagrams>
<Diagram Name="EntityDataModel" >
<EntityTypeShape EntityType="EntityDataModel.Purchase" Width="1.5" PointX="2.125" PointY="0.875" Height="1.211080729166667" />
<EntityTypeShape EntityType="EntityDataModel.PurchaseLine" Width="1.5" PointX="3.625" PointY="3" Height="1.0187792968749996" />
<AssociationConnector Association="EntityDataModel.PurchasePurchaseLine">
<ConnectorPoint PointX="2.84375" PointY="2.086080729166667" />
<ConnectorPoint PointX="2.84375" PointY="3.6055403645833333" />
<ConnectorPoint PointX="3.625" PointY="3.6055403645833333" /></AssociationConnector></Diagram></edmx:Diagrams>
</edmx:Designer>
</edmx:Edmx>
@@ -28,11 +28,77 @@ using System.Collections.Generic;
using System.Text;
using Newtonsoft.Json.Utilities;
using NUnit.Framework;
using System.IO;
using System.Linq;
namespace Newtonsoft.Json.Tests
{
public class JavaScriptConvertTest : TestFixtureBase
{
#if Entities
[Test]
public void EntitiesTest()
{
Purchase purchase = new Purchase() { Id = 1 };
purchase.PurchaseLine.Add(new PurchaseLine() { Id = 1, Purchase = purchase });
purchase.PurchaseLine.Add(new PurchaseLine() { Id = 2, Purchase = purchase });
StringWriter sw = new StringWriter();
JsonSerializer serializer = new JsonSerializer();
serializer.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
using (JsonWriter jw = new JsonTextWriter(sw))
{
jw.Formatting = Formatting.Indented;
serializer.Serialize(jw, purchase);
}
string json = sw.ToString();
Assert.AreEqual(@"{
""Id"": 1,
""PurchaseLine"": [
{
""Id"": 1,
""PurchaseReference"": {
""EntityKey"": null,
""RelationshipName"": ""EntityDataModel.PurchasePurchaseLine"",
""SourceRoleName"": ""PurchaseLine"",
""TargetRoleName"": ""Purchase"",
""RelationshipSet"": null,
""IsLoaded"": false
},
""EntityState"": 1,
""EntityKey"": null
},
{
""Id"": 2,
""PurchaseReference"": {
""EntityKey"": null,
""RelationshipName"": ""EntityDataModel.PurchasePurchaseLine"",
""SourceRoleName"": ""PurchaseLine"",
""TargetRoleName"": ""Purchase"",
""RelationshipSet"": null,
""IsLoaded"": false
},
""EntityState"": 1,
""EntityKey"": null
}
],
""EntityState"": 1,
""EntityKey"": null
}", json);
Purchase newPurchase = JavaScriptConvert.DeserializeObject<Purchase>(json);
Assert.AreEqual(1, newPurchase.Id);
Assert.AreEqual(2, newPurchase.PurchaseLine.Count);
Assert.AreEqual(1, newPurchase.PurchaseLine.ElementAt(0).Id);
Assert.AreEqual(2, newPurchase.PurchaseLine.ElementAt(1).Id);
}
#endif
[Test]
public void EscapeJavaScriptString()
{
@@ -51,9 +51,13 @@
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Data" />
<Reference Include="System.Data.Entity">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Runtime.Serialization">
<RequiredTargetFramework>3.0</RequiredTargetFramework>
</Reference>
<Reference Include="System.Security" />
<Reference Include="System.ServiceModel">
<RequiredTargetFramework>3.0</RequiredTargetFramework>
</Reference>
@@ -84,6 +88,7 @@
<Compile Include="Linq\JTokenTests.cs" />
<Compile Include="Linq\JValueTests.cs" />
<Compile Include="Linq\LinqToJsonTest.cs" />
<Compile Include="PerformanceTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SilverlightTests.cs" />
<Compile Include="TestFixtureBase.cs" />
@@ -0,0 +1,182 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Data;
using System.Diagnostics;
using Newtonsoft.Json;
using System.IO;
using System.Web.Script.Serialization;
using NUnit.Framework;
namespace Newtonsoft.Json.Tests
{
/// <summary>
/// Summary description for JsonSerializerTest
/// </summary>
public class PerformanceTests : TestFixtureBase
{
private DateTime BaseDate = DateTime.Parse("01/01/2000");
//JSONSerializer ser = null;
public string SerializeJsonNet(object value)
{
Type type = value.GetType();
Newtonsoft.Json.JsonSerializer json = new Newtonsoft.Json.JsonSerializer();
json.NullValueHandling = NullValueHandling.Ignore;
json.ObjectCreationHandling = Newtonsoft.Json.ObjectCreationHandling.Replace;
json.MissingMemberHandling = Newtonsoft.Json.MissingMemberHandling.Ignore;
json.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
StringWriter sw = new StringWriter();
Newtonsoft.Json.JsonTextWriter writer = new JsonTextWriter(sw);
if (false)
writer.Formatting = Formatting.Indented;
else
writer.Formatting = Formatting.None;
writer.QuoteChar = '"';
json.Serialize(writer, value);
string output = sw.ToString();
writer.Close();
return output;
}
public string SerializeWebExtensions(object value)
{
JavaScriptSerializer ser = new JavaScriptSerializer();
List<JavaScriptConverter> converters = new List<JavaScriptConverter>();
return ser.Serialize(value);
}
[Test]
public void PerformanceTest2()
{
TestClass test = new TestClass();
test.Address1.Address = "fff Street";
test.Address1.Entered = DateTime.Now.AddDays(20);
test.BigNumber = 34123123123.121M;
test.Now = DateTime.Now.AddHours(1);
test.strings = new List<string>() { "Rick", "Markus egger ][, (2nd)", "Kevin McNeish" };
cAddress address = new cAddress();
address.Entered = DateTime.Now.AddDays(-1);
address.Address = "array address";
test.Addresses.Add(address);
address = new cAddress();
address.Entered = DateTime.Now.AddDays(-2);
address.Address = "array 2 address";
test.Addresses.Add(address);
Stopwatch timed = new Stopwatch();
timed.Start();
string json = null;
for (int x = 0; x < 10000; x++)
{
json = this.SerializeJsonNet(test);
//json = this.SerializeWebExtensions(test);
}
timed.Stop();
Console.WriteLine("{0}", timed.ElapsedMilliseconds + " ms");
Console.WriteLine("{0}", json);
}
}
public class TestClass
{
public string Name
{
get { return _Name; }
set { _Name = value; }
}
private string _Name = "Rick";
public DateTime Now
{
get { return _Now; }
set { _Now = value; }
}
private DateTime _Now = DateTime.Now;
public decimal BigNumber
{
get { return _BigNumber; }
set { _BigNumber = value; }
}
private decimal _BigNumber = 1212121.22M;
public cAddress Address1
{
get { return _Address1; }
set { _Address1 = value; }
}
private cAddress _Address1 = new cAddress();
public List<cAddress> Addresses
{
get { return _Addresses; }
set { _Addresses = value; }
}
private List<cAddress> _Addresses = new List<cAddress>();
public List<string> strings = new List<string>() { "Rick", "Markus", "Kevin" };
public Dictionary<string, int> dictionary = new Dictionary<string, int> { { "Val asd1", 1 }, { "Val2", 3 }, { "Val3", 4 } };
}
public class cAddress
{
public string Address
{
get { return _Address; }
set { _Address = value; }
}
private string _Address = "32 Kaiea";
public string Phone
{
get { return _Phone; }
set { _Phone = value; }
}
private string _Phone = "(503) 814-6335";
public DateTime Entered
{
get { return _Entered; }
set { _Entered = value; }
}
private DateTime _Entered = DateTime.Parse("01/01/2007", CultureInfo.CurrentCulture.DateTimeFormat);
}
}
@@ -36,15 +36,15 @@ namespace Newtonsoft.Json
_converterType = converterType;
}
internal JsonConverter CreateJsonConverterInstance()
internal static JsonConverter CreateJsonConverterInstance(Type converterType)
{
try
{
return (JsonConverter)Activator.CreateInstance(_converterType);
return (JsonConverter)Activator.CreateInstance(converterType);
}
catch (Exception ex)
{
throw new Exception("Error creating {0}".FormatWith(CultureInfo.InvariantCulture, _converterType), ex);
throw new Exception("Error creating {0}".FormatWith(CultureInfo.InvariantCulture, converterType), ex);
}
}
}
+24 -11
View File
@@ -44,13 +44,15 @@ namespace Newtonsoft.Json
/// </summary>
public class JsonSerializer
{
private static readonly Dictionary<ICustomAttributeProvider, Type> ConverterTypeCache = new Dictionary<ICustomAttributeProvider, Type>();
private static Dictionary<Type, MemberMappingCollection> TypeMemberMappings = new Dictionary<Type,MemberMappingCollection>();
private ReferenceLoopHandling _referenceLoopHandling;
private MissingMemberHandling _missingMemberHandling;
private ObjectCreationHandling _objectCreationHandling;
private NullValueHandling _nullValueHandling;
private int _level;
private JsonConverterCollection _converters;
private Dictionary<Type, MemberMappingCollection> _typeMemberMappings;
/// <summary>
/// Get or set how reference loops (e.g. a class referencing itself) is handled.
@@ -255,7 +257,7 @@ namespace Newtonsoft.Json
if (existingValue == null)
value = CreateAndPopulateList(reader, objectType);
else
value = PopulateList(CollectionUtils.CreateListWrapper(existingValue), ReflectionUtils.GetListItemType(objectType), reader);
value = PopulateList(CollectionUtils.CreateCollectionWrapper(existingValue), ReflectionUtils.GetCollectionItemType(objectType), reader);
}
else
{
@@ -317,16 +319,13 @@ namespace Newtonsoft.Json
private MemberMappingCollection GetMemberMappings(Type objectType)
{
if (_typeMemberMappings == null)
_typeMemberMappings = new Dictionary<Type, MemberMappingCollection>();
MemberMappingCollection memberMappings;
if (_typeMemberMappings.TryGetValue(objectType, out memberMappings))
if (TypeMemberMappings.TryGetValue(objectType, out memberMappings))
return memberMappings;
memberMappings = CreateMemberMappings(objectType);
_typeMemberMappings[objectType] = memberMappings;
TypeMemberMappings[objectType] = memberMappings;
return memberMappings;
}
@@ -388,11 +387,25 @@ namespace Newtonsoft.Json
private JsonConverter GetConverter(ICustomAttributeProvider attributeProvider, Type targetConvertedType)
{
JsonConverterAttribute converterAttribute = ReflectionUtils.GetAttribute<JsonConverterAttribute>(attributeProvider, true);
Type converterType;
if (converterAttribute != null)
if (!ConverterTypeCache.ContainsKey(attributeProvider))
{
JsonConverter memberConverter = converterAttribute.CreateJsonConverterInstance();
JsonConverterAttribute converterAttribute = ReflectionUtils.GetAttribute<JsonConverterAttribute>(attributeProvider, true);
converterType = (converterAttribute != null)
? converterAttribute.ConverterType
: null;
ConverterTypeCache[attributeProvider] = converterType;
}
else
{
converterType = ConverterTypeCache[attributeProvider];
}
if (converterType != null)
{
JsonConverter memberConverter = JsonConverterAttribute.CreateJsonConverterInstance(converterType);
if (!memberConverter.CanConvert(targetConvertedType))
throw new JsonSerializationException("JsonConverter {0} on {1} is not compatible with member type {2}.".FormatWith(CultureInfo.InvariantCulture, memberConverter.GetType().Name, attributeProvider, targetConvertedType.Name));
@@ -490,7 +503,7 @@ namespace Newtonsoft.Json
private object CreateAndPopulateList(JsonReader reader, Type objectType)
{
return CollectionUtils.CreateAndPopulateList(objectType, l => PopulateList(l, ReflectionUtils.GetListItemType(objectType), reader));
return CollectionUtils.CreateAndPopulateList(objectType, l => PopulateList(l, ReflectionUtils.GetCollectionItemType(objectType), reader));
}
private IList PopulateList(IList list, Type listItemType, JsonReader reader)
@@ -116,6 +116,7 @@
<Compile Include="NullValueHandling.cs" />
<Compile Include="ReferenceLoopHandling.cs" />
<Compile Include="Utilities\ConvertUtils.cs" />
<Compile Include="Utilities\CollectionWrapper.cs" />
<Compile Include="Utilities\DateTimeUtils.cs" />
<Compile Include="Utilities\DictionaryWrapper.cs" />
<Compile Include="Utilities\JavaScriptUtils.cs" />
@@ -366,6 +366,33 @@ namespace Newtonsoft.Json.Utilities
return false;
}
public static IWrappedCollection CreateCollectionWrapper(object list)
{
ValidationUtils.ArgumentNotNull(list, "list");
Type collectionDefinition;
if (ReflectionUtils.IsSubClass(list.GetType(), typeof(ICollection<>), out collectionDefinition))
{
Type collectionItemType = ReflectionUtils.GetCollectionItemType(collectionDefinition);
// Activator.CreateInstance throws AmbiguousMatchException. Manually invoke constructor
Func<Type, IList<object>, object> instanceCreator = (t, a) =>
{
ConstructorInfo c = t.GetConstructor(new[] { collectionDefinition });
return c.Invoke(new[] { list });
};
return (IWrappedCollection)ReflectionUtils.CreateGeneric(typeof(CollectionWrapper<>), new[] { collectionItemType }, instanceCreator, list);
}
else if (list is IList)
{
return new CollectionWrapper<object>((IList)list);
}
else
{
throw new Exception("Can not create ListWrapper for type {0}.".FormatWith(CultureInfo.InvariantCulture, list.GetType()));
}
}
public static IWrappedList CreateListWrapper(object list)
{
ValidationUtils.ArgumentNotNull(list, "list");
@@ -373,7 +400,7 @@ namespace Newtonsoft.Json.Utilities
Type listDefinition;
if (ReflectionUtils.IsSubClass(list.GetType(), typeof(IList<>), out listDefinition))
{
Type listItemType = ReflectionUtils.GetListItemType(listDefinition);
Type collectionItemType = ReflectionUtils.GetCollectionItemType(listDefinition);
// Activator.CreateInstance throws AmbiguousMatchException. Manually invoke constructor
Func<Type, IList<object>, object> instanceCreator = (t, a) =>
@@ -382,7 +409,7 @@ namespace Newtonsoft.Json.Utilities
return c.Invoke(new[] { list });
};
return (IWrappedList)ReflectionUtils.CreateGeneric(typeof(ListWrapper<>), new[] { listItemType }, instanceCreator, list);
return (IWrappedList)ReflectionUtils.CreateGeneric(typeof(ListWrapper<>), new[] { collectionItemType }, instanceCreator, list);
}
else if (list is IList)
{
@@ -478,7 +505,7 @@ namespace Newtonsoft.Json.Utilities
}
else if (listType.IsGenericType && listType.GetGenericTypeDefinition() == typeof(IList<>))
{
list = CollectionUtils.CreateGenericList(ReflectionUtils.GetListItemType(listType));
list = CollectionUtils.CreateGenericList(ReflectionUtils.GetCollectionItemType(listType));
}
else
{
@@ -494,7 +521,7 @@ namespace Newtonsoft.Json.Utilities
if (isReadOnlyOrFixedSize)
{
if (listType.IsArray)
list = ToArray(((List<object>)list).ToArray(), ReflectionUtils.GetListItemType(listType));
list = ToArray(((List<object>)list).ToArray(), ReflectionUtils.GetCollectionItemType(listType));
else if (ReflectionUtils.IsSubClass(listType, typeof(ReadOnlyCollection<>)))
list = (IList)Activator.CreateInstance(listType, list);
}
@@ -0,0 +1,268 @@
#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;
using System.Collections.Generic;
using System.Threading;
using Newtonsoft.Json.Utilities;
using System.Linq;
using System.Globalization;
namespace Newtonsoft.Json.Utilities
{
internal interface IWrappedCollection : IList
{
object UnderlyingCollection { get; }
}
internal class CollectionWrapper<T> : ICollection<T>, IWrappedCollection
{
private readonly IList _list;
private readonly ICollection<T> _genericCollection;
private object _syncRoot;
public CollectionWrapper(IList list)
{
ValidationUtils.ArgumentNotNull(list, "list");
_list = list;
}
public CollectionWrapper(ICollection<T> list)
{
ValidationUtils.ArgumentNotNull(list, "list");
_genericCollection = list;
}
public void Add(T item)
{
if (_genericCollection != null)
_genericCollection.Add(item);
else
_list.Add(item);
}
public void Clear()
{
if (_genericCollection != null)
_genericCollection.Clear();
else
_list.Clear();
}
public bool Contains(T item)
{
if (_genericCollection != null)
return _genericCollection.Contains(item);
else
return _list.Contains(item);
}
public void CopyTo(T[] array, int arrayIndex)
{
if (_genericCollection != null)
_genericCollection.CopyTo(array, arrayIndex);
else
_list.CopyTo(array, arrayIndex);
}
public int Count
{
get
{
if (_genericCollection != null)
return _genericCollection.Count;
else
return _list.Count;
}
}
public bool IsReadOnly
{
get
{
if (_genericCollection != null)
return _genericCollection.IsReadOnly;
else
return _list.IsReadOnly;
}
}
public bool Remove(T item)
{
if (_genericCollection != null)
{
return _genericCollection.Remove(item);
}
else
{
bool contains = _list.Contains(item);
if (contains)
_list.Remove(item);
return contains;
}
}
public IEnumerator<T> GetEnumerator()
{
if (_genericCollection != null)
return _genericCollection.GetEnumerator();
return _list.Cast<T>().GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
if (_genericCollection != null)
return _genericCollection.GetEnumerator();
else
return _list.GetEnumerator();
}
int IList.Add(object value)
{
VerifyValueType(value);
Add((T)value);
return (Count - 1);
}
bool IList.Contains(object value)
{
if (IsCompatibleObject(value))
return Contains((T)value);
return false;
}
int IList.IndexOf(object value)
{
if (_genericCollection != null)
throw new Exception("Wrapped ICollection<T> does not support IndexOf.");
if (IsCompatibleObject(value))
return _list.IndexOf((T)value);
return -1;
}
void IList.RemoveAt(int index)
{
if (_genericCollection != null)
throw new Exception("Wrapped ICollection<T> does not support RemoveAt.");
_list.RemoveAt(index);
}
void IList.Insert(int index, object value)
{
if (_genericCollection != null)
throw new Exception("Wrapped ICollection<T> does not support Insert.");
VerifyValueType(value);
_list.Insert(index, (T)value);
}
bool IList.IsFixedSize
{
get { return false; }
}
void IList.Remove(object value)
{
if (IsCompatibleObject(value))
Remove((T)value);
}
object IList.this[int index]
{
get
{
if (_genericCollection != null)
throw new Exception("Wrapped ICollection<T> does not support indexer.");
return _list[index];
}
set
{
if (_genericCollection != null)
throw new Exception("Wrapped ICollection<T> does not support indexer.");
VerifyValueType(value);
_list[index] = (T)value;
}
}
void ICollection.CopyTo(Array array, int arrayIndex)
{
CopyTo((T[])array, arrayIndex);
}
bool ICollection.IsSynchronized
{
get { return false; }
}
object ICollection.SyncRoot
{
get
{
if (_syncRoot == null)
Interlocked.CompareExchange(ref _syncRoot, new object(), null);
return _syncRoot;
}
}
private static void VerifyValueType(object value)
{
if (!IsCompatibleObject(value))
throw new ArgumentException("The value '{0}' is not of type '{1}' and cannot be used in this generic collection.".FormatWith(CultureInfo.InvariantCulture, value, typeof(T)), "value");
}
private static bool IsCompatibleObject(object value)
{
if (!(value is T) && (value != null || typeof(T).IsValueType))
return false;
return true;
}
public object UnderlyingCollection
{
get
{
if (_genericCollection != null)
return _genericCollection;
else
return _list;
}
}
}
}
@@ -181,11 +181,11 @@ namespace Newtonsoft.Json.Utilities
}
/// <summary>
/// Gets the type of the typed list's items.
/// Gets the type of the typed collection's items.
/// </summary>
/// <param name="type">The type.</param>
/// <returns>The type of the typed list's items.</returns>
public static Type GetListItemType(Type type)
/// <returns>The type of the typed collection's items.</returns>
public static Type GetCollectionItemType(Type type)
{
ValidationUtils.ArgumentNotNull(type, "type");
Type genericListType;
@@ -194,10 +194,10 @@ namespace Newtonsoft.Json.Utilities
{
return type.GetElementType();
}
else if (IsSubClass(type, typeof(IList<>), out genericListType))
else if (IsSubClass(type, typeof(ICollection<>), out genericListType))
{
if (genericListType.IsGenericTypeDefinition)
throw new Exception("Type {0} is not a list.".FormatWith(CultureInfo.InvariantCulture, type));
throw new Exception("Type {0} is not a collection.".FormatWith(CultureInfo.InvariantCulture, type));
return genericListType.GetGenericArguments()[0];
}
@@ -207,7 +207,7 @@ namespace Newtonsoft.Json.Utilities
}
else
{
throw new Exception("Type {0} is not a list.".FormatWith(CultureInfo.InvariantCulture, type));
throw new Exception("Type {0} is not a collection.".FormatWith(CultureInfo.InvariantCulture, type));
}
}
@@ -266,7 +266,7 @@ namespace Newtonsoft.Json.Utilities
{
ValidationUtils.ArgumentNotNull(list, "list");
Type elementType = GetListItemType(list.GetType());
Type elementType = GetCollectionItemType(list.GetType());
if (elementType.IsValueType)
{