From 5c0431464be353671d2c3b9607018fbf34045657 Mon Sep 17 00:00:00 2001 From: JamesNK Date: Wed, 17 Nov 2010 07:31:20 +0000 Subject: [PATCH] -Fix to preserve collection type information in certain situations when serializing -Add missing Newtonsoft.Json.WindowsPhone.sln file --- .../Serialization/JsonSerializerTest.cs | 64 ++++++++++++++++++- Src/Newtonsoft.Json.WindowsPhone.sln | 31 +++++++++ .../Serialization/JsonArrayContract.cs | 39 ++++++++--- 3 files changed, 122 insertions(+), 12 deletions(-) create mode 100644 Src/Newtonsoft.Json.WindowsPhone.sln diff --git a/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs b/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs index 5ece94df..cc804918 100644 --- a/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs +++ b/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs @@ -3795,11 +3795,11 @@ keyword such as type of business."" public void DeserializeNullableStruct() { NullableStructPropertyClass nullableStructPropertyClass = new NullableStructPropertyClass(); - nullableStructPropertyClass.Foo1 = new StructISerializable() {Name = "foo 1"}; - nullableStructPropertyClass.Foo2 = new StructISerializable() {Name = "foo 2"}; + nullableStructPropertyClass.Foo1 = new StructISerializable() { Name = "foo 1" }; + nullableStructPropertyClass.Foo2 = new StructISerializable() { Name = "foo 2" }; NullableStructPropertyClass barWithNull = new NullableStructPropertyClass(); - barWithNull.Foo1 = new StructISerializable() {Name = "foo 1"}; + barWithNull.Foo1 = new StructISerializable() { Name = "foo 1" }; barWithNull.Foo2 = null; //throws error on deserialization because bar1.Foo2 is of type Foo? @@ -3827,5 +3827,63 @@ keyword such as type of business."" }); } #endif + + [Test] + public void SerializingIEnumerableOfTShouldRetainGenericTypeInfo() + { + CustomEnumerable products = new CustomEnumerable(); + + string json = JsonConvert.SerializeObject(products, Formatting.Indented, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All }); + + Assert.AreEqual(@"{ + ""$type"": ""Newtonsoft.Json.Tests.TestObjects.Product[], Newtonsoft.Json.Tests"", + ""$values"": [] +}", json); + } + + public class CustomEnumerable : IEnumerable + { + //NOTE: a simple linked list + private readonly T value; + private readonly CustomEnumerable next; + private readonly int count; + + private CustomEnumerable(T value, CustomEnumerable next) + { + this.value = value; + this.next = next; + count = this.next.count + 1; + } + + public CustomEnumerable() + { + count = 0; + } + + public CustomEnumerable AddFirst(T newVal) + { + return new CustomEnumerable(newVal, this); + } + + public IEnumerator GetEnumerator() + { + if (count == 0) // last node + yield break; + yield return value; + + var nextInLine = next; + while (nextInLine != null) + { + if (nextInLine.count != 0) + yield return nextInLine.value; + nextInLine = nextInLine.next; + } + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + } } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json.WindowsPhone.sln b/Src/Newtonsoft.Json.WindowsPhone.sln new file mode 100644 index 00000000..dfc12d97 --- /dev/null +++ b/Src/Newtonsoft.Json.WindowsPhone.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Lib", "Lib", "{F69285DD-24FB-4A60-AE8B-4C2744285D0F}" + ProjectSection(SolutionItems) = preProject + Lib\NUnit\Silverlight\nunit.framework.dll = Lib\NUnit\Silverlight\nunit.framework.dll + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Newtonsoft.Json.WindowsPhone", "Newtonsoft.Json\Newtonsoft.Json.WindowsPhone.csproj", "{7A7F70AB-5C07-47ED-BDD2-ECC14DBACA5E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Newtonsoft.Json.Tests.WindowsPhone", "Newtonsoft.Json.Tests\Newtonsoft.Json.Tests.WindowsPhone.csproj", "{5ED71C8C-D0A6-487C-9A8C-BB855ECEAF75}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {7A7F70AB-5C07-47ED-BDD2-ECC14DBACA5E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7A7F70AB-5C07-47ED-BDD2-ECC14DBACA5E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7A7F70AB-5C07-47ED-BDD2-ECC14DBACA5E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7A7F70AB-5C07-47ED-BDD2-ECC14DBACA5E}.Release|Any CPU.Build.0 = Release|Any CPU + {5ED71C8C-D0A6-487C-9A8C-BB855ECEAF75}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5ED71C8C-D0A6-487C-9A8C-BB855ECEAF75}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5ED71C8C-D0A6-487C-9A8C-BB855ECEAF75}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5ED71C8C-D0A6-487C-9A8C-BB855ECEAF75}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Src/Newtonsoft.Json/Serialization/JsonArrayContract.cs b/Src/Newtonsoft.Json/Serialization/JsonArrayContract.cs index 81375318..01aede8e 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonArrayContract.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonArrayContract.cs @@ -77,19 +77,40 @@ namespace Newtonsoft.Json.Serialization if (_genericCollectionDefinitionType != null) { - if (_genericWrapperType == null) - { - _genericWrapperType = ReflectionUtils.MakeGenericType(typeof (CollectionWrapper<>), CollectionItemType); - - ConstructorInfo genericWrapperConstructor = _genericWrapperType.GetConstructor(new[] {_genericCollectionDefinitionType}); - _genericWrapperCreator = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall(genericWrapperConstructor); - } - + EnsureGenericWrapperCreator(); return (IWrappedCollection) _genericWrapperCreator(null, list); } else { - return new CollectionWrapper((IList)((IEnumerable)list).Cast().ToList()); + IList values = ((IEnumerable) list).Cast().ToList(); + + if (CollectionItemType != null) + { + Array array = Array.CreateInstance(CollectionItemType, values.Count); + for (int i = 0; i < values.Count; i++) + { + array.SetValue(values[i], i); + } + + values = array; + } + + return new CollectionWrapper(values); + } + } + + private void EnsureGenericWrapperCreator() + { + if (_genericWrapperType == null) + { + _genericWrapperType = ReflectionUtils.MakeGenericType(typeof (CollectionWrapper<>), CollectionItemType); + + Type constructorArgument = (ReflectionUtils.InheritsGenericDefinition(_genericCollectionDefinitionType, typeof (List<>))) + ? ReflectionUtils.MakeGenericType(typeof (ICollection<>), CollectionItemType) + : _genericCollectionDefinitionType; + + ConstructorInfo genericWrapperConstructor = _genericWrapperType.GetConstructor(new[] { constructorArgument }); + _genericWrapperCreator = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall(genericWrapperConstructor); } }