Explorar o código

Support for serializing interface types eg: Json.Parse<IEnumerable<string>>

Brad Robinson %!s(int64=11) %!d(string=hai) anos
pai
achega
ac4b0104e9
Modificáronse 4 ficheiros con 123 adicións e 2 borrados
  1. 36 2
      PetaJson.cs
  2. 1 0
      TestCases/TestCases.csproj
  3. 74 0
      TestCases/TestConcreteFromInterface.cs
  4. 12 0
      readme.md

+ 36 - 2
PetaJson.cs

@@ -702,8 +702,12 @@ namespace PetaJson
                     return listType.GetMethod("ToArray").Invoke(list, null);
                 }
 
+                // Convert interfaces to concrete types
+                if (type.IsInterface)
+                    type = Utils.ResolveInterfaceToClass(type);
+
                 // Untyped dictionary?
-                if (_tokenizer.CurrentToken == Token.OpenBrace && (type.IsAssignableFrom(typeof(Dictionary<string, object>))))
+                if (_tokenizer.CurrentToken == Token.OpenBrace && (type.IsAssignableFrom(typeof(IDictionary<string, object>))))
                 {
 #if !PETAJSON_NO_DYNAMIC
                     var container = (new ExpandoObject()) as IDictionary<string, object>;
@@ -717,7 +721,7 @@ namespace PetaJson
 
                     return container;
                 }
-
+               
                 // Untyped list?
                 if (_tokenizer.CurrentToken == Token.OpenSquare && (type.IsAssignableFrom(typeof(List<object>))))
                 {
@@ -1673,6 +1677,36 @@ namespace PetaJson
                 return false;
             }
 
+            public static Type ResolveInterfaceToClass(Type tItf)
+            {
+                // Generic type
+                if (tItf.IsGenericType)
+                {
+                    var genDef = tItf.GetGenericTypeDefinition();
+
+                    // IList<> -> List<>
+                    if (genDef == typeof(IList<>))
+                    {
+                        return typeof(List<>).MakeGenericType(tItf.GetGenericArguments());
+                    }
+
+                    // IDictionary<string,> -> Dictionary<string,>
+                    if (genDef == typeof(IDictionary<,>) && tItf.GetGenericArguments()[0] == typeof(string))
+                    {
+                        return typeof(Dictionary<,>).MakeGenericType(tItf.GetGenericArguments());
+                    }
+                }
+
+                // IEnumerable -> List<object>
+                if (tItf == typeof(IEnumerable))
+                    return typeof(List<object>);
+
+                // IDicitonary -> Dictionary<string,object>
+                if (tItf == typeof(IDictionary))
+                    return typeof(Dictionary<string, object>);
+                return tItf;
+            }
+
             public static long ToUnixMilliseconds(DateTime This)
             {
                 return (long)This.Subtract(new DateTime(1970, 1, 1)).TotalMilliseconds;

+ 1 - 0
TestCases/TestCases.csproj

@@ -51,6 +51,7 @@
     <Compile Include="Program.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="TestAbstractTypes.cs" />
+    <Compile Include="TestConcreteFromInterface.cs" />
     <Compile Include="TestCustomFormat.cs" />
     <Compile Include="TestNullableTypes.cs" />
     <Compile Include="TestOptions.cs" />

+ 74 - 0
TestCases/TestConcreteFromInterface.cs

@@ -0,0 +1,74 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using PetaTest;
+using PetaJson;
+using System.Collections;
+
+namespace TestCases
+{
+    [TestFixture]
+    class TestConcreteFromInterface
+    {
+        [Test]
+        public void TestGenericList()
+        {
+            var l = new List<int>() { 10, 20, 30 };
+
+            var json = Json.Format(l);
+
+            var l2 = Json.Parse<IList<int>>(json);
+            Assert.IsInstanceOf(typeof(List<int>), l2);
+
+            Assert.AreEquivalent(l, l2);
+        }
+
+        [Test]
+        public void TestGenericDictionary()
+        {
+            var l = new Dictionary<string,int>() { 
+                {"A", 10}, 
+                {"B", 20},
+                {"C", 30}
+            };
+
+            var json = Json.Format(l);
+
+            var l2 = Json.Parse<IDictionary<string,int>>(json);
+            Assert.IsInstanceOf(typeof(Dictionary<string,int>), l2);
+
+            Assert.AreEquivalent(l, l2);
+        }
+
+        [Test]
+        public void TestObjectList()
+        {
+            var l = new List<int>() { 10, 20, 30 };
+
+            var json = Json.Format(l);
+
+            var l2 = Json.Parse<IList>(json);
+            Assert.IsInstanceOf(typeof(List<object>), l2);
+
+            Assert.AreEqual(l.Count, l2.Count);
+        }
+
+        [Test]
+        public void TestObjectDictionary()
+        {
+            var l = new Dictionary<string, int>() { 
+                {"A", 10}, 
+                {"B", 20},
+                {"C", 30}
+            };
+
+            var json = Json.Format(l);
+
+            var l2 = Json.Parse<IDictionary>(json);
+            Assert.IsInstanceOf(typeof(Dictionary<string,object>), l2);
+            Assert.AreEqual(l.Count, l2.Count);
+        }
+
+    }
+}

+ 12 - 0
readme.md

@@ -452,6 +452,18 @@ imagine a situation where a numeric ID field was incorrectly provided by a serve
 Note: although these event methods could have been implemented using reflection rather than interfaces,
 the use of interfaces is more discoverable through Intellisense/Autocomplete.
 
+## Cloning Objects
+
+PetaJson includes a couple of helper functions for cloning object:
+
+	var person1 = new Person() { Name = "Mr Json Bourne"; }
+	var person2 = Json.Clone(person1);
+
+You can also clone into an existing instance
+
+	var person3 = new Person();
+	Json.CloneInto(person3, person1);		// Copies from person1 to person3
+
 ## Options
 
 PetaJson has a couple of formatting/parsing options. These can be set as global defaults: