diff --git a/src/Binaron.Serializer.Debug/Program.cs b/src/Binaron.Serializer.Debug/Program.cs index e201967..d73d8a1 100644 --- a/src/Binaron.Serializer.Debug/Program.cs +++ b/src/Binaron.Serializer.Debug/Program.cs @@ -2,6 +2,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Linq; using System.Text; @@ -25,6 +26,28 @@ public TestObject(int a) } } + class TestObject1 + { + public int? A { get; set; } + + public TestObject1() + { + + } + + public TestObject1(int? a) + { + A = a; + } + } + + enum E1 + { + E11, + E12, + E13 + }; + class Collector : IEnumerable { private List mData = new List(); @@ -41,18 +64,197 @@ class Collector : IEnumerable public static void Main(string[] args) { - Collector c = new Collector() { new TestObject(1), new TestObject(2) }; - using (var ms1 = new MemoryStream()) + if (false) + Benchmark(); + + if (false) { - BinaronConvert.Serialize(c, ms1); - using (var ms2 = new MemoryStream(ms1.ToArray())) + Collector c = new Collector() { new TestObject(1), new TestObject(2) }; + using (var ms1 = new MemoryStream()) { - var c2 = BinaronConvert.Deserialize>(ms2); - ; + BinaronConvert.Serialize(c, ms1); + using (var ms2 = new MemoryStream(ms1.ToArray())) + { + var cr = BinaronConvert.Deserialize>(ms2); + ; + } } } - + if (true) + { + Collector c = new Collector() { new TestObject1(1), null, new TestObject1(null), new TestObject1(2) }; + using (var ms1 = new MemoryStream()) + { + BinaronConvert.Serialize(c, ms1); + using (var ms2 = new MemoryStream(ms1.ToArray())) + { + var cr = BinaronConvert.Deserialize>(ms2); + ; + } + } + } + + if (false) + { + Collector c1 = new Collector() { E1.E11, E1.E12, E1.E13 }; + using (var ms1 = new MemoryStream()) + { + BinaronConvert.Serialize(c1, ms1); + using (var ms2 = new MemoryStream(ms1.ToArray())) + { + var cr1 = BinaronConvert.Deserialize>(ms2); + ; + } + } + } + + if (false) + { + List l = new List() { new TestObject(1), null, new TestObject(2) }; + using (var ms1 = new MemoryStream()) + { + BinaronConvert.Serialize(l, ms1); + using (var ms2 = new MemoryStream(ms1.ToArray())) + { + var l1 = BinaronConvert.Deserialize>(ms2); + ; + } + } + } + + if (false) + { + List c2 = new List() { 1, null, 2 }; + using (var ms1 = new MemoryStream()) + { + BinaronConvert.Serialize(c2, ms1); + using (var ms2 = new MemoryStream(ms1.ToArray())) + { + var cr2 = BinaronConvert.Deserialize>(ms2); + ; + } + } + } + + if (true) + { + Collector c2 = new Collector() { 1, null, 2 }; + using (var ms1 = new MemoryStream()) + { + BinaronConvert.Serialize(c2, ms1); + using (var ms2 = new MemoryStream(ms1.ToArray())) + { + var cr2 = BinaronConvert.Deserialize>(ms2); + ; + } + + using (var ms2 = new MemoryStream(ms1.ToArray())) + { + var cr2 = BinaronConvert.Deserialize(ms2); + ; + } + } + } + + if (false) + { + using (var ms1 = new MemoryStream()) + { + BinaronConvert.Serialize(1, ms1); + using (var ms2 = new MemoryStream(ms1.ToArray())) + { + var cr2 = BinaronConvert.Deserialize(ms2); + ; + } + } + + using (var ms1 = new MemoryStream()) + { + BinaronConvert.Serialize(null, ms1); + using (var ms2 = new MemoryStream(ms1.ToArray())) + { + var cr2 = BinaronConvert.Deserialize(ms2); + ; + } + } + } + + + + + } + + private static void Benchmark() + { + Stopwatch sw = new Stopwatch(); + + { + sw.Reset(); + Collector c = new Collector(); + for (int i = 0; i < 1000; i++) + c.Add(i); + sw.Start(); + for (int i = 0; i < 1000; i++) + { + using (var ms1 = new MemoryStream()) + { + BinaronConvert.Serialize(c, ms1); + using (var ms2 = new MemoryStream(ms1.ToArray())) + { + var c2 = BinaronConvert.Deserialize>(ms2); + } + } + } + sw.Stop(); + Console.WriteLine("IEnumerable/invoke {0}", sw.ElapsedMilliseconds); + } + + { + sw.Reset(); + Collector c = new Collector(); + for (int i = 0; i < 1000; i++) + c.Add((short)i); + sw.Start(); + for (int i = 0; i < 1000; i++) + { + using (var ms1 = new MemoryStream()) + { + BinaronConvert.Serialize(c, ms1); + using (var ms2 = new MemoryStream(ms1.ToArray())) + { + var c2 = BinaronConvert.Deserialize>(ms2); + } + } + } + sw.Stop(); + Console.WriteLine("IEnumerable/reflection {0}", sw.ElapsedMilliseconds); + } + + { + sw.Reset(); + List c = new List(); + for (int i = 0; i < 1000; i++) + c.Add(i); + sw.Start(); + for (int i = 0; i < 1000; i++) + { + using (var ms1 = new MemoryStream()) + { + BinaronConvert.Serialize(c, ms1); + using (var ms2 = new MemoryStream(ms1.ToArray())) + { + var c2 = BinaronConvert.Deserialize>(ms2); + } + } + } + sw.Stop(); + Console.WriteLine("List {0}", sw.ElapsedMilliseconds); + } + + + + } } } diff --git a/src/Binaron.Serializer.Tests/CustomTestCollection.cs b/src/Binaron.Serializer.Tests/CustomTestCollection.cs index 1bcb5d0..ebea1de 100644 --- a/src/Binaron.Serializer.Tests/CustomTestCollection.cs +++ b/src/Binaron.Serializer.Tests/CustomTestCollection.cs @@ -9,18 +9,18 @@ namespace Binaron.Serializer.Tests { public class CustomTestCollection : IEnumerable { - private List mList = new List(); + private List List = new List(); - public T this[int index] => mList[index]; + public T this[int index] => List[index]; - public int Count => mList.Count; + public int Count => List.Count; - public void Add(T value) => mList.Add(value); + public void Add(T value) => List.Add(value); - public IEnumerator GetEnumerator() => mList.GetEnumerator(); + public IEnumerator GetEnumerator() => List.GetEnumerator(); - IEnumerator IEnumerable.GetEnumerator() => mList.GetEnumerator(); + IEnumerator IEnumerable.GetEnumerator() => List.GetEnumerator(); public class TestCollectionObject { diff --git a/src/Binaron.Serializer.Tests/ListSerializationTests.cs b/src/Binaron.Serializer.Tests/ListSerializationTests.cs index fc688e3..d53edd6 100644 --- a/src/Binaron.Serializer.Tests/ListSerializationTests.cs +++ b/src/Binaron.Serializer.Tests/ListSerializationTests.cs @@ -283,23 +283,20 @@ public void CustomCollectionIntTest() Assert.AreEqual(4, dest[4]); } - [Test] - public void CustomCollectionStringTest() + [TestCaseSource(typeof(AllTestCases), nameof(AllTestCases.TestCaseOfValues))] + public void CustomCollectionOfTypeTest(TSource v) { - CustomTestCollection collection = new CustomTestCollection() + CustomTestCollection collection = new CustomTestCollection() { - "0", "1", "2", "3", "4" + v }; - var dest = Tester.TestRoundTrip>(collection); - Assert.AreEqual(5, dest.Count); - Assert.AreEqual("0", dest[0]); - Assert.AreEqual("1", dest[1]); - Assert.AreEqual("2", dest[2]); - Assert.AreEqual("3", dest[3]); - Assert.AreEqual("4", dest[4]); + var dest = Tester.TestRoundTrip>(collection); + Assert.AreEqual(1, dest.Count); + Assert.AreEqual(v, dest[0]); } + [Test] public void CustomCollectionObjectTest() { @@ -320,5 +317,63 @@ public void CustomCollectionObjectTest() Assert.AreEqual(3, dest[3].A); Assert.AreEqual(4, dest[4].A); } + + [Test] + public void TestListWithNullInside() + { + CustomTestCollection.TestCollectionObject> collection = new CustomTestCollection.TestCollectionObject>() + { + new CustomTestCollection.TestCollectionObject(0), + new CustomTestCollection.TestCollectionObject(1), + null, + new CustomTestCollection.TestCollectionObject(3), + new CustomTestCollection.TestCollectionObject(4), + }; + + var dest = Tester.TestRoundTrip(collection); + Assert.AreEqual(5, dest.Count); + Assert.AreEqual(0, dest[0].A); + Assert.AreEqual(1, dest[1].A); + Assert.AreEqual(null, dest[2]); + Assert.AreEqual(3, dest[3].A); + Assert.AreEqual(4, dest[4].A); + } + + [Test] + public void TestListOfNullables1() + { + var collection = new CustomTestCollection() { 1, null, 2 }; + using (var ms1 = new MemoryStream()) + { + var so = new SerializerOptions(); + BinaronConvert.Serialize(collection, ms1, so); + using (var ms2 = new MemoryStream(ms1.ToArray())) + { + var cr2 = BinaronConvert.Deserialize>(ms2); + Assert.AreEqual(3, cr2.Count); + Assert.AreEqual(1, cr2[0]); + Assert.AreEqual(null, cr2[1]); + Assert.AreEqual(2, cr2[2]); + } + } + } + [Test] + public void TestListOfNullables2() + { + var collection = new List() { 1, null, 2 }; + using (var ms1 = new MemoryStream()) + { + var so = new SerializerOptions(); + BinaronConvert.Serialize(collection, ms1, so); + using (var ms2 = new MemoryStream(ms1.ToArray())) + { + var cr2 = BinaronConvert.Deserialize>(ms2); + Assert.AreEqual(3, cr2.Count); + Assert.AreEqual(1, cr2[0]); + Assert.AreEqual(null, cr2[1]); + Assert.AreEqual(2, cr2[2]); + } + } + } } } \ No newline at end of file diff --git a/src/Binaron.Serializer.Tests/MemberGetSetterTests.cs b/src/Binaron.Serializer.Tests/MemberGetSetterTests.cs index b84bc5a..7fe6eff 100644 --- a/src/Binaron.Serializer.Tests/MemberGetSetterTests.cs +++ b/src/Binaron.Serializer.Tests/MemberGetSetterTests.cs @@ -49,5 +49,6 @@ public int NoRead set { } } } + } } \ No newline at end of file diff --git a/src/Binaron.Serializer.Tests/ValueSerializationTests.cs b/src/Binaron.Serializer.Tests/ValueSerializationTests.cs index 24e1172..24a15dc 100644 --- a/src/Binaron.Serializer.Tests/ValueSerializationTests.cs +++ b/src/Binaron.Serializer.Tests/ValueSerializationTests.cs @@ -394,6 +394,68 @@ private static object GetEnumNumeric(object source) } } + [TestCase(1)] + [TestCase(null)] + public void NullableTest1(int? value) + { + using (var ms1 = new MemoryStream()) + { + BinaronConvert.Serialize(value, ms1); + using (var ms2 = new MemoryStream(ms1.ToArray())) + { + Assert.AreEqual(value, BinaronConvert.Deserialize(ms2)); + + } + } + } + + [TestCase(1, "a")] + [TestCase(null, null)] + [TestCase(1, null)] + [TestCase(null, "abcd")] + + public void MemberSetterNullableType1(int? v1, string v2) + { + TestClass1 tc1 = new TestClass1() { IntValue = v1, StringValue = v2 }; + using (MemoryStream ms = new MemoryStream()) + { + BinaronConvert.Serialize(tc1, ms); + using (MemoryStream ms1 = new MemoryStream(ms.ToArray())) + { + var tc2 = BinaronConvert.Deserialize(ms1); + Assert.AreEqual(v1, tc2.IntValue); + Assert.AreEqual(v2, tc2.StringValue); + } + } + } + + [TestCase(1, "a")] + [TestCase(null, null)] + [TestCase(1, null)] + [TestCase(null, "abcd")] + + public void MemberSetterNullableType2(int? v1, string v2) + { + List tc1 = new List() { new TestClass1() { IntValue = v1, StringValue = v2 } }; + using (MemoryStream ms = new MemoryStream()) + { + BinaronConvert.Serialize(tc1, ms); + using (MemoryStream ms1 = new MemoryStream(ms.ToArray())) + { + var tc2 = BinaronConvert.Deserialize>(ms1); + Assert.AreEqual(1, tc2.Count); + Assert.AreEqual(v1, tc2[0].IntValue); + Assert.AreEqual(v2, tc2[0].StringValue); + } + } + } + + private class TestClass1 + { + public int? IntValue { get; set; } + public string StringValue { get; set; } + } + private class TestClass { public DateTime RootValue { get; set; } diff --git a/src/Binaron.Serializer/Infrastructure/EnumerableWrapperWithAdd.cs b/src/Binaron.Serializer/Infrastructure/EnumerableWrapperWithAdd.cs new file mode 100644 index 0000000..27cc0a1 --- /dev/null +++ b/src/Binaron.Serializer/Infrastructure/EnumerableWrapperWithAdd.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq.Expressions; +using System.Reflection.Emit; +using System.Runtime.CompilerServices; + +namespace Binaron.Serializer.Infrastructure +{ + internal class EnumerableWrapperWithAdd + { + private readonly Action Action; + private readonly object Result; + public bool HasAddAction { get; private set; } = false; + + public EnumerableWrapperWithAdd(IEnumerable result) + { + Result = result; + var method = result.GetType().GetMethod("Add", new Type[] { typeof(T) }); + + if (method == null) + Action = (o, v) => { }; + else + { + HasAddAction = true; + DynamicMethod action = new DynamicMethod( + "Add", + null, + new Type[] { typeof(object), typeof(T) }, + this.GetType().Module); + + var il = action.GetILGenerator(); + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ldarg_1); + il.Emit(method.IsVirtual ? OpCodes.Callvirt : OpCodes.Call, method); + il.Emit(OpCodes.Ret); + + Action = (Action)action.CreateDelegate(typeof(Action)); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Add(T value) + { + Action(Result, value); + } + } +} \ No newline at end of file diff --git a/src/Binaron.Serializer/Infrastructure/GenericReader.cs b/src/Binaron.Serializer/Infrastructure/GenericReader.cs index 1bef71e..7ede49c 100644 --- a/src/Binaron.Serializer/Infrastructure/GenericReader.cs +++ b/src/Binaron.Serializer/Infrastructure/GenericReader.cs @@ -58,8 +58,9 @@ internal static class GenericReader return typeof(T).IsArray ? ToArray(l) : result; } - else if (result is IEnumerable l1) + else if (result is IEnumerable e1) { + var l1 = new EnumerableWrapperWithAdd(e1); var valueType = Reader.ReadSerializedType(reader); while (Reader.ReadEnumerableType(reader) == EnumerableType.HasItem) { @@ -96,8 +97,9 @@ internal static class GenericReader return typeof(T).IsArray ? ToArray(l) : result; } - else if (result is IEnumerable l1) + else if (result is IEnumerable e1) { + var l1 = new EnumerableWrapperWithAdd(e1); var valueType = Reader.ReadSerializedType(reader); if (valueType == SerializedType.Bool) { @@ -143,8 +145,9 @@ internal static class GenericReader return typeof(T).IsArray ? ToArray(l) : result; } - else if (result is IEnumerable l1) + else if (result is IEnumerable e1) { + var l1 = new EnumerableWrapperWithAdd(e1); var valueType = Reader.ReadSerializedType(reader); if (valueType == SerializedType.Byte) { @@ -189,8 +192,9 @@ internal static class GenericReader return typeof(T).IsArray ? ToArray(l) : result; } - else if (result is IEnumerable l1) + else if (result is IEnumerable e1) { + var l1 = new EnumerableWrapperWithAdd(e1); var valueType = Reader.ReadSerializedType(reader); if (valueType == SerializedType.Char) { @@ -236,8 +240,9 @@ internal static class GenericReader return typeof(T).IsArray ? ToArray(l) : result; } - else if (result is IEnumerable l1) + else if (result is IEnumerable e1) { + var l1 = new EnumerableWrapperWithAdd(e1); var valueType = Reader.ReadSerializedType(reader); if (valueType == SerializedType.DateTime) { @@ -283,8 +288,9 @@ internal static class GenericReader return typeof(T).IsArray ? ToArray(l) : result; } - else if (result is IEnumerable l1) + else if (result is IEnumerable e1) { + var l1 = new EnumerableWrapperWithAdd(e1); var valueType = Reader.ReadSerializedType(reader); if (valueType == SerializedType.Guid) { @@ -330,8 +336,9 @@ internal static class GenericReader return typeof(T).IsArray ? ToArray(l) : result; } - else if (result is IEnumerable l1) + else if (result is IEnumerable e1) { + var l1 = new EnumerableWrapperWithAdd(e1); var valueType = Reader.ReadSerializedType(reader); if (valueType == SerializedType.Decimal) { @@ -377,8 +384,9 @@ internal static class GenericReader return typeof(T).IsArray ? ToArray(l) : result; } - else if (result is IEnumerable l1) + else if (result is IEnumerable e1) { + var l1 = new EnumerableWrapperWithAdd(e1); var valueType = Reader.ReadSerializedType(reader); if (valueType == SerializedType.Double) { @@ -424,8 +432,9 @@ internal static class GenericReader return typeof(T).IsArray ? ToArray(l) : result; } - else if (result is IEnumerable l1) + else if (result is IEnumerable e1) { + var l1 = new EnumerableWrapperWithAdd(e1); var valueType = Reader.ReadSerializedType(reader); if (valueType == SerializedType.Short) { @@ -471,8 +480,9 @@ internal static class GenericReader return typeof(T).IsArray ? ToArray(l) : result; } - else if (result is IEnumerable l1) + else if (result is IEnumerable e1) { + var l1 = new EnumerableWrapperWithAdd(e1); var valueType = Reader.ReadSerializedType(reader); if (valueType == SerializedType.Int) { @@ -518,8 +528,9 @@ internal static class GenericReader return typeof(T).IsArray ? ToArray(l) : result; } - else if (result is IEnumerable l1) + else if (result is IEnumerable e1) { + var l1 = new EnumerableWrapperWithAdd(e1); var valueType = Reader.ReadSerializedType(reader); if (valueType == SerializedType.Long) { @@ -565,8 +576,9 @@ internal static class GenericReader return typeof(T).IsArray ? ToArray(l) : result; } - else if (result is IEnumerable l1) + else if (result is IEnumerable e1) { + var l1 = new EnumerableWrapperWithAdd(e1); var valueType = Reader.ReadSerializedType(reader); if (valueType == SerializedType.SByte) { @@ -612,8 +624,9 @@ internal static class GenericReader return typeof(T).IsArray ? ToArray(l) : result; } - else if (result is IEnumerable l1) + else if (result is IEnumerable e1) { + var l1 = new EnumerableWrapperWithAdd(e1); var valueType = Reader.ReadSerializedType(reader); if (valueType == SerializedType.Float) { @@ -658,8 +671,9 @@ internal static class GenericReader return typeof(T).IsArray ? ToArray(l) : result; } - else if (result is IEnumerable l1) + else if (result is IEnumerable e1) { + var l1 = new EnumerableWrapperWithAdd(e1); var valueType = Reader.ReadSerializedType(reader); if (valueType == SerializedType.String) { @@ -704,8 +718,9 @@ internal static class GenericReader return typeof(T).IsArray ? ToArray(l) : result; } - else if (result is IEnumerable l1) + else if (result is IEnumerable e1) { + var l1 = new EnumerableWrapperWithAdd(e1); var valueType = Reader.ReadSerializedType(reader); if (valueType == SerializedType.UShort) { @@ -751,8 +766,9 @@ internal static class GenericReader return typeof(T).IsArray ? ToArray(l) : result; } - else if (result is IEnumerable l1) + else if (result is IEnumerable e1) { + var l1 = new EnumerableWrapperWithAdd(e1); var valueType = Reader.ReadSerializedType(reader); if (valueType == SerializedType.UInt) { @@ -799,8 +815,9 @@ internal static class GenericReader return typeof(T).IsArray ? ToArray(l) : result; } - else if (result is IEnumerable l1) + else if (result is IEnumerable e1) { + var l1 = new EnumerableWrapperWithAdd(e1); var valueType = Reader.ReadSerializedType(reader); if (valueType == SerializedType.ULong) { @@ -847,8 +864,9 @@ internal static class GenericReader return typeof(T).IsArray ? ToArray(l) : result; } - else if (result is IEnumerable l1) + else if (result is IEnumerable e1) { + var l1 = new EnumerableWrapperWithAdd(e1); while (Reader.ReadEnumerableType(reader) == EnumerableType.HasItem) { var valueType = Reader.ReadSerializedType(reader); @@ -877,8 +895,9 @@ internal static class GenericReader return typeof(T).IsArray ? ToArray(l) : result; } - else if (result is IEnumerable l1) + else if (result is IEnumerable e1) { + var l1 = new EnumerableWrapperWithAdd(e1); while (Reader.ReadEnumerableType(reader) == EnumerableType.HasItem) { var valueType = Reader.ReadSerializedType(reader); @@ -908,8 +927,9 @@ internal static class GenericReader return typeof(T).IsArray ? ToArray(l) : result; } - else if (result is IEnumerable l1) + else if (result is IEnumerable e1) { + var l1 = new EnumerableWrapperWithAdd(e1); while (Reader.ReadEnumerableType(reader) == EnumerableType.HasItem) { var valueType = Reader.ReadSerializedType(reader); @@ -939,8 +959,9 @@ internal static class GenericReader return typeof(T).IsArray ? ToArray(l) : result; } - else if (result is IEnumerable l1) + else if (result is IEnumerable e1) { + var l1 = new EnumerableWrapperWithAdd(e1); while (Reader.ReadEnumerableType(reader) == EnumerableType.HasItem) { var valueType = Reader.ReadSerializedType(reader); @@ -970,8 +991,9 @@ internal static class GenericReader return typeof(T).IsArray ? ToArray(l) : result; } - else if (result is IEnumerable l1) + else if (result is IEnumerable e1) { + var l1 = new EnumerableWrapperWithAdd(e1); while (Reader.ReadEnumerableType(reader) == EnumerableType.HasItem) { var valueType = Reader.ReadSerializedType(reader); @@ -1001,8 +1023,9 @@ internal static class GenericReader return typeof(T).IsArray ? ToArray(l) : result; } - else if (result is IEnumerable l1) + else if (result is IEnumerable e1) { + var l1 = new EnumerableWrapperWithAdd(e1); while (Reader.ReadEnumerableType(reader) == EnumerableType.HasItem) { var valueType = Reader.ReadSerializedType(reader); @@ -1032,8 +1055,9 @@ internal static class GenericReader return typeof(T).IsArray ? ToArray(l) : result; } - else if (result is IEnumerable l1) + else if (result is IEnumerable e1) { + var l1 = new EnumerableWrapperWithAdd(e1); while (Reader.ReadEnumerableType(reader) == EnumerableType.HasItem) { var valueType = Reader.ReadSerializedType(reader); @@ -1063,8 +1087,9 @@ internal static class GenericReader return typeof(T).IsArray ? ToArray(l) : result; } - else if (result is IEnumerable l1) + else if (result is IEnumerable e1) { + var l1 = new EnumerableWrapperWithAdd(e1); while (Reader.ReadEnumerableType(reader) == EnumerableType.HasItem) { var valueType = Reader.ReadSerializedType(reader); @@ -1094,8 +1119,9 @@ internal static class GenericReader return typeof(T).IsArray ? ToArray(l) : result; } - else if (result is IEnumerable l1) + else if (result is IEnumerable e1) { + var l1 = new EnumerableWrapperWithAdd(e1); while (Reader.ReadEnumerableType(reader) == EnumerableType.HasItem) { var valueType = Reader.ReadSerializedType(reader); @@ -1110,23 +1136,24 @@ internal static class GenericReader Discarder.Discard(reader); return result; } - case TypeCode.Int32: - { - var result = CreateResultObject(); - if (result is ICollection l) - { - while (Reader.ReadEnumerableType(reader) == EnumerableType.HasItem) - { - var valueType = Reader.ReadSerializedType(reader); - var v = SelfUpgradingReader.ReadAsInt(reader, valueType); - if (v.HasValue) - l.Add(v.Value); - } - - return typeof(T).IsArray ? ToArray(l) : result; - } - else if (result is IEnumerable l1) + case TypeCode.Int32: + { + var result = CreateResultObject(); + if (result is ICollection l) + { + while (Reader.ReadEnumerableType(reader) == EnumerableType.HasItem) + { + var valueType = Reader.ReadSerializedType(reader); + var v = SelfUpgradingReader.ReadAsInt(reader, valueType); + if (v.HasValue) + l.Add(v.Value); + } + + return typeof(T).IsArray ? ToArray(l) : result; + } + else if (result is IEnumerable e1) { + var l1 = new EnumerableWrapperWithAdd(e1); while (Reader.ReadEnumerableType(reader) == EnumerableType.HasItem) { var valueType = Reader.ReadSerializedType(reader); @@ -1138,9 +1165,9 @@ internal static class GenericReader return result; } - Discarder.Discard(reader); - return result; - } + Discarder.Discard(reader); + return result; + } case TypeCode.Int64: { var result = CreateResultObject(); @@ -1156,8 +1183,9 @@ internal static class GenericReader return typeof(T).IsArray ? ToArray(l) : result; } - else if (result is IEnumerable l1) + else if (result is IEnumerable e1) { + var l1 = new EnumerableWrapperWithAdd(e1); while (Reader.ReadEnumerableType(reader) == EnumerableType.HasItem) { var valueType = Reader.ReadSerializedType(reader); @@ -1187,8 +1215,9 @@ internal static class GenericReader return typeof(T).IsArray ? ToArray(l) : result; } - else if (result is IEnumerable l1) + else if (result is IEnumerable e1) { + var l1 = new EnumerableWrapperWithAdd(e1); while (Reader.ReadEnumerableType(reader) == EnumerableType.HasItem) { var valueType = Reader.ReadSerializedType(reader); @@ -1218,8 +1247,9 @@ internal static class GenericReader return typeof(T).IsArray ? ToArray(l) : result; } - else if (result is IEnumerable l1) + else if (result is IEnumerable e1) { + var l1 = new EnumerableWrapperWithAdd(e1); while (Reader.ReadEnumerableType(reader) == EnumerableType.HasItem) { var valueType = Reader.ReadSerializedType(reader); @@ -1234,22 +1264,23 @@ internal static class GenericReader Discarder.Discard(reader); return result; } - case TypeCode.String: - { - var result = CreateResultObject(); - if (result is ICollection l) - { - while (Reader.ReadEnumerableType(reader) == EnumerableType.HasItem) - { - var valueType = Reader.ReadSerializedType(reader); - var v = SelfUpgradingReader.ReadAsString(reader, valueType); - l.Add(v); - } - - return typeof(T).IsArray ? ToArray(l) : result; - } - else if (result is IEnumerable l1) + case TypeCode.String: + { + var result = CreateResultObject(); + if (result is ICollection l) + { + while (Reader.ReadEnumerableType(reader) == EnumerableType.HasItem) + { + var valueType = Reader.ReadSerializedType(reader); + var v = SelfUpgradingReader.ReadAsString(reader, valueType); + l.Add(v); + } + + return typeof(T).IsArray ? ToArray(l) : result; + } + else if (result is IEnumerable e1) { + var l1 = new EnumerableWrapperWithAdd(e1); while (Reader.ReadEnumerableType(reader) == EnumerableType.HasItem) { var valueType = Reader.ReadSerializedType(reader); @@ -1260,26 +1291,27 @@ internal static class GenericReader return result; } - Discarder.Discard(reader); - return result; - } - case TypeCode.UInt16: - { - var result = CreateResultObject(); - if (result is ICollection l) - { - while (Reader.ReadEnumerableType(reader) == EnumerableType.HasItem) - { - var valueType = Reader.ReadSerializedType(reader); - var v = SelfUpgradingReader.ReadAsUShort(reader, valueType); - if (v.HasValue) - l.Add(v.Value); - } - - return typeof(T).IsArray ? ToArray(l) : result; - } - else if (result is IEnumerable l1) + Discarder.Discard(reader); + return result; + } + case TypeCode.UInt16: + { + var result = CreateResultObject(); + if (result is ICollection l) { + while (Reader.ReadEnumerableType(reader) == EnumerableType.HasItem) + { + var valueType = Reader.ReadSerializedType(reader); + var v = SelfUpgradingReader.ReadAsUShort(reader, valueType); + if (v.HasValue) + l.Add(v.Value); + } + + return typeof(T).IsArray ? ToArray(l) : result; + } + else if (result is IEnumerable e1) + { + var l1 = new EnumerableWrapperWithAdd(e1); while (Reader.ReadEnumerableType(reader) == EnumerableType.HasItem) { var valueType = Reader.ReadSerializedType(reader); @@ -1291,9 +1323,9 @@ internal static class GenericReader return result; } - Discarder.Discard(reader); - return result; - } + Discarder.Discard(reader); + return result; + } case TypeCode.UInt32: { var result = CreateResultObject(); @@ -1309,8 +1341,9 @@ internal static class GenericReader return typeof(T).IsArray ? ToArray(l) : result; } - else if (result is IEnumerable l1) + else if (result is IEnumerable e1) { + var l1 = new EnumerableWrapperWithAdd(e1); while (Reader.ReadEnumerableType(reader) == EnumerableType.HasItem) { var valueType = Reader.ReadSerializedType(reader); @@ -1340,8 +1373,9 @@ internal static class GenericReader return typeof(T).IsArray ? ToArray(l) : result; } - else if (result is IEnumerable l1) + else if (result is IEnumerable e1) { + var l1 = new EnumerableWrapperWithAdd(e1); while (Reader.ReadEnumerableType(reader) == EnumerableType.HasItem) { var valueType = Reader.ReadSerializedType(reader); @@ -1455,8 +1489,36 @@ private static class EnumerableAdder { public static (bool Success, object Result) AddEnums(ReaderState reader, object list, bool convertToArray) where T : struct { - if (!(list is ICollection l)) - return (false, list); + if (!(list is ICollection l)) + { + if (!(list is IEnumerable e)) + return (false, list); + + EnumerableWrapperWithAdd adder = new EnumerableWrapperWithAdd(e); + if (!adder.HasAddAction) + return (false, list); + + do + { + try + { + while (Reader.ReadEnumerableType(reader) == EnumerableType.HasItem) + { + var val = ReadEnum(reader); + if (val.HasValue) + adder.Add(val.Value); + } + break; + } + catch (InvalidCastException) + { + } + catch (OverflowException) + { + } + } while (true); + return (true, list); + } do { diff --git a/src/Binaron.Serializer/Infrastructure/GenericWriter.cs b/src/Binaron.Serializer/Infrastructure/GenericWriter.cs index 5d97204..3da3022 100644 --- a/src/Binaron.Serializer/Infrastructure/GenericWriter.cs +++ b/src/Binaron.Serializer/Infrastructure/GenericWriter.cs @@ -40,7 +40,7 @@ public void Write(WriterState writer, IEnumerable list) foreach (var item in (IEnumerable) list) { writer.Write((byte) EnumerableType.HasItem); - Serializer.WriteNonPrimitive(writer, item); + Serializer.WriteValue(writer, item); } writer.Write((byte) EnumerableType.End); } @@ -312,8 +312,18 @@ private class GenericListWriter : IGenericListWriter { public void Write(WriterState writer, ICollection list) { - foreach (var item in (ICollection) list) - Serializer.WriteNonPrimitive(writer, item); + var type = typeof(T); + var type1 = Nullable.GetUnderlyingType(type); + if (type1 != null && type1 != type) + { + foreach (var item in (ICollection)list) + Serializer.WriteValue(writer, item); + } + else + { + foreach (var item in (ICollection)list) + Serializer.WriteNonPrimitive(writer, item); + } } } } diff --git a/src/Binaron.Serializer/Infrastructure/IEnumerableExtension.cs b/src/Binaron.Serializer/Infrastructure/IEnumerableExtension.cs deleted file mode 100644 index 114db1f..0000000 --- a/src/Binaron.Serializer/Infrastructure/IEnumerableExtension.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Runtime.CompilerServices; - -namespace Binaron.Serializer.Infrastructure -{ - internal static class IEnumerableExtension - { - private static ConcurrentDictionary> gAdders = new ConcurrentDictionary>(); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Add(this IEnumerable enumerable, T value) - { - if (!gAdders.TryGetValue(enumerable.GetType(), out Action action)) - { - var method = enumerable.GetType().GetMethod("Add", new Type[] { typeof(T) }); - if (method == null) - action = (o, v) => { }; - else - action = (o, v) => method.Invoke(o, new object[] { v }); - gAdders.TryAdd(enumerable.GetType(), action); - } - action(enumerable, value); - } - } -} \ No newline at end of file diff --git a/src/Binaron.Serializer/Serializer.cs b/src/Binaron.Serializer/Serializer.cs index 1d6ca76..3670b41 100644 --- a/src/Binaron.Serializer/Serializer.cs +++ b/src/Binaron.Serializer/Serializer.cs @@ -102,22 +102,30 @@ private static void WriteNonPrimitive(WriterState writer, object val) [MethodImpl(MethodImplOptions.AggressiveInlining)] private static void WriteObject(WriterState writer, T val) { - var type = val.GetType(); - if (writer.CustomObjectIdentifierProviders == null || !writer.CustomObjectIdentifierProviders.TryGetValue(typeof(T), out var customObjectIdentifierProvider)) - { - writer.Write((byte) SerializedType.Object); + if (val == null) + { + writer.Write((byte)SerializedType.Null); } - else - { - writer.Write((byte) SerializedType.CustomObject); - WriteValue(writer, customObjectIdentifierProvider.GetIdentifier(type)); + else + { + var type = val.GetType(); + if (writer.CustomObjectIdentifierProviders == null || !writer.CustomObjectIdentifierProviders.TryGetValue(typeof(T), out var customObjectIdentifierProvider)) + { + writer.Write((byte)SerializedType.Object); + } + else + { + writer.Write((byte)SerializedType.CustomObject); + WriteValue(writer, customObjectIdentifierProvider.GetIdentifier(type)); + } + + + var getters = type == typeof(T) ? GetterHandler.GetterHandlers.Getters : GetterHandler.GetGetterHandlers(type); + foreach (var getter in getters) + getter.Handle(writer, val); + writer.Write((byte)EnumerableType.End); } - - var getters = type == typeof(T) ? GetterHandler.GetterHandlers.Getters : GetterHandler.GetGetterHandlers(type); - foreach (var getter in getters) - getter.Handle(writer, val); - - writer.Write((byte) EnumerableType.End); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -242,14 +250,24 @@ private static void WriteEnumerableFallback(WriterState writer, IEnumerable enum [MethodImpl(MethodImplOptions.AggressiveInlining)] private static bool WritePrimitive(WriterState writer, object value) - { - return WritePrimitive(writer, value.GetType().GetTypeCode(), value); + { + var type = value.GetType(); + var type1 = Nullable.GetUnderlyingType(type); + if (type1 != null && type1 != type) + type = type1; + + return WritePrimitive(writer, type.GetTypeCode(), value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static bool WritePrimitive(WriterState writer, T value) { - return WritePrimitive(writer, TypeOf.TypeCode, value); + var type = typeof(T); + var type1 = Nullable.GetUnderlyingType(type); + if (type1 != null && type1 != type) + type = type1; + + return WritePrimitive(writer, type.GetTypeCode(), value); } [MethodImpl(MethodImplOptions.AggressiveInlining)]