From 30637dab84a829c0a1273043a1308d29afc6254a Mon Sep 17 00:00:00 2001 From: Alihan Livdumlu Date: Wed, 27 Sep 2017 19:06:06 +0200 Subject: [PATCH] feat: support tuple format in structs and classes --- Assets/Plugins/UnityJSON/Deserializer.cs | 17 +++- Assets/Plugins/UnityJSON/Enums.cs | 45 +++++++--- Assets/Plugins/UnityJSON/Instantiater.cs | 70 ++++++++++----- Assets/Plugins/UnityJSON/JSON.cs | 106 +++++++++++++++++++++++ Assets/Plugins/UnityJSON/Serializer.cs | 53 ++++++++---- README.md | 106 +++++++++++++++++------ unityjson.unitypackage | Bin 26294 -> 27071 bytes 7 files changed, 315 insertions(+), 82 deletions(-) diff --git a/Assets/Plugins/UnityJSON/Deserializer.cs b/Assets/Plugins/UnityJSON/Deserializer.cs index 0e747a8..142107b 100644 --- a/Assets/Plugins/UnityJSON/Deserializer.cs +++ b/Assets/Plugins/UnityJSON/Deserializer.cs @@ -65,6 +65,10 @@ public Instantiater instantiater { } } + protected Deserializer () + { + } + /// /// Tries to deserialize the JSON node onto the given object. It is guaranteed /// that the object is not null. This will be called before trying any other @@ -1360,12 +1364,17 @@ private Dictionary> _GetDeserializedClassMembers ( out MemberInfo extrasMember, out JSONExtrasAttribute extrasAttribute) { - JSONObjectAttribute classAttribute = Util.GetAttribute (classType); + JSONObjectAttribute objectAttribute = Util.GetAttribute (classType); Dictionary> members = new Dictionary> (); var flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance; - if (classAttribute != null && !classAttribute.options.ShouldIgnoreStatic ()) { - flags |= BindingFlags.Static; + if (objectAttribute != null) { + if (!objectAttribute.options.ShouldIgnoreStatic ()) { + flags |= BindingFlags.Static; + } + if (objectAttribute.options.ShouldUseTupleFormat ()) { + throw new ArgumentException ("Cannot deserialize on a tuple formatted object."); + } } extrasMember = null; @@ -1392,7 +1401,7 @@ private Dictionary> _GetDeserializedClassMembers ( } } - if (classAttribute == null || !classAttribute.options.ShouldIgnoreProperties ()) { + if (objectAttribute == null || !objectAttribute.options.ShouldIgnoreProperties ()) { foreach (var propertyInfo in classType.GetProperties(flags)) { if (extrasMember == null) { if (Util.IsJSONExtrasMember (propertyInfo, out extrasAttribute)) { diff --git a/Assets/Plugins/UnityJSON/Enums.cs b/Assets/Plugins/UnityJSON/Enums.cs index 0b16345..a77ed86 100644 --- a/Assets/Plugins/UnityJSON/Enums.cs +++ b/Assets/Plugins/UnityJSON/Enums.cs @@ -116,7 +116,20 @@ public enum ObjectOptions /// keys, then an exception is thrown. This option prevents the /// deserializer from throwing that exception. /// - IgnoreUnknownKey = 1 << 2 + IgnoreUnknownKey = 1 << 2, + + /// + /// The class or the struct is handled as a tuple (JSON array) rather + /// than a dictionary. This automatically ignores properties both for + /// serialization and deserialization. For serialization, the fields are + /// serialized in the order they are defined in an array without keys. + /// As for deserialization, the elements are passed to the constructor + /// in the order they are defined. Deserialization does not take place + /// for other fields and properties. + /// + /// Tuple formatted classes and structs do not support JSON extras. + /// + TupleFormat = 1 << 3 | IgnoreProperties, } /// @@ -225,7 +238,7 @@ public static bool IsDeserialized (this NodeOptions options) /// public static bool ShouldSerializeNull (this NodeOptions options) { - return (options & NodeOptions.SerializeNull) != 0; + return (options & NodeOptions.SerializeNull) == NodeOptions.SerializeNull; } /// @@ -233,7 +246,7 @@ public static bool ShouldSerializeNull (this NodeOptions options) /// public static bool ShouldIgnoreTypeMismatch (this NodeOptions options) { - return (options & NodeOptions.IgnoreTypeMismatch) != 0; + return (options & NodeOptions.IgnoreTypeMismatch) == NodeOptions.IgnoreTypeMismatch; } /// @@ -241,7 +254,7 @@ public static bool ShouldIgnoreTypeMismatch (this NodeOptions options) /// public static bool ShouldIgnoreUnknownType (this NodeOptions options) { - return (options & NodeOptions.IgnoreInstantiationError) != 0; + return (options & NodeOptions.IgnoreInstantiationError) == NodeOptions.IgnoreInstantiationError; } /// @@ -257,7 +270,7 @@ public static bool ShouldAssignNull (this NodeOptions options) /// public static bool ShouldReplaceWithDeserialized (this NodeOptions options) { - return (options & NodeOptions.ReplaceDeserialized) != 0; + return (options & NodeOptions.ReplaceDeserialized) == NodeOptions.ReplaceDeserialized; } /// @@ -265,7 +278,7 @@ public static bool ShouldReplaceWithDeserialized (this NodeOptions options) /// public static bool ShouldIgnoreProperties (this ObjectOptions options) { - return (options & ObjectOptions.IgnoreProperties) != 0; + return (options & ObjectOptions.IgnoreProperties) == ObjectOptions.IgnoreProperties; } /// @@ -284,12 +297,20 @@ public static bool ShouldThrowAtUnknownKey (this ObjectOptions options) return (options & ObjectOptions.IgnoreUnknownKey) == 0; } + /// + /// Returns true if ObjectOptions.TupleFormat is not set. + /// + public static bool ShouldUseTupleFormat (this ObjectOptions options) + { + return (options & ObjectOptions.TupleFormat) == ObjectOptions.TupleFormat; + } + /// /// Returns true if ObjectTypes.String is set. /// public static bool SupportsString (this ObjectTypes types) { - return (types & ObjectTypes.String) != 0; + return (types & ObjectTypes.String) == ObjectTypes.String; } /// @@ -297,7 +318,7 @@ public static bool SupportsString (this ObjectTypes types) /// public static bool SupportsBool (this ObjectTypes types) { - return (types & ObjectTypes.Bool) != 0; + return (types & ObjectTypes.Bool) == ObjectTypes.Bool; } /// @@ -305,7 +326,7 @@ public static bool SupportsBool (this ObjectTypes types) /// public static bool SupportsNumber (this ObjectTypes types) { - return (types & ObjectTypes.Number) != 0; + return (types & ObjectTypes.Number) == ObjectTypes.Number; } /// @@ -313,7 +334,7 @@ public static bool SupportsNumber (this ObjectTypes types) /// public static bool SupportsArray (this ObjectTypes types) { - return (types & ObjectTypes.Array) != 0; + return (types & ObjectTypes.Array) == ObjectTypes.Array; } /// @@ -321,7 +342,7 @@ public static bool SupportsArray (this ObjectTypes types) /// public static bool SupportsDictionary (this ObjectTypes types) { - return (types & ObjectTypes.Dictionary) != 0; + return (types & ObjectTypes.Dictionary) == ObjectTypes.Dictionary; } /// @@ -329,7 +350,7 @@ public static bool SupportsDictionary (this ObjectTypes types) /// public static bool SupportsCustom (this ObjectTypes types) { - return (types & ObjectTypes.Custom) != 0; + return (types & ObjectTypes.Custom) == ObjectTypes.Custom; } } } diff --git a/Assets/Plugins/UnityJSON/Instantiater.cs b/Assets/Plugins/UnityJSON/Instantiater.cs index 6f8ec68..5b4b0a3 100644 --- a/Assets/Plugins/UnityJSON/Instantiater.cs +++ b/Assets/Plugins/UnityJSON/Instantiater.cs @@ -75,6 +75,10 @@ public class Instantiater { public static readonly Instantiater Default = new Instantiater (); + protected Instantiater () + { + } + /// /// Instantiates an instance of a type. First, TryInstantiate method is /// called for custom instantiation. If that fails, then the class is queried for @@ -252,22 +256,28 @@ private InstantiationData _Instantiate ( return instantiationData; } + if (node.IsNull || node.Tag == JSONNodeType.None) { + return InstantiationData.Null; + } + if (referingType != targetType) { - var conditionalAttributes = targetType - .GetCustomAttributes (typeof(ConditionalInstantiationAttribute), false); - foreach (object attribute in conditionalAttributes) { - var condition = attribute as ConditionalInstantiationAttribute; - if (Equals (node [condition.key].Value, condition.value.ToString ())) { - instantiationData = _Instantiate ( - node, - condition.referenceType, - targetType, - options, - deserializer); - if (condition.ignoreConditionKey) { - instantiationData.ignoredKeys = new HashSet () { condition.key }; + if (node.IsObject) { + var conditionalAttributes = targetType + .GetCustomAttributes (typeof(ConditionalInstantiationAttribute), false); + foreach (object attribute in conditionalAttributes) { + var condition = attribute as ConditionalInstantiationAttribute; + if (Equals (node [condition.key].Value, condition.value.ToString ())) { + instantiationData = _Instantiate ( + node, + condition.referenceType, + targetType, + options, + deserializer); + if (condition.ignoreConditionKey) { + instantiationData.ignoredKeys = new HashSet () { condition.key }; + } + return instantiationData; } - return instantiationData; } } @@ -295,6 +305,19 @@ private InstantiationData _InstantiateWithConstructor ( NodeOptions options, Deserializer deserializer) { + if (node.IsNull || node.Tag == JSONNodeType.None) { + return InstantiationData.Null; + } + + JSONObjectAttribute objectAttribute = Util.GetAttribute (targetType); + bool useTupleFormat = objectAttribute != null + ? objectAttribute.options.ShouldUseTupleFormat () : false; + if (useTupleFormat && !node.IsArray) { + throw new InstantiationException ("Expected JSON array, found " + node.Tag); + } else if (!useTupleFormat && !node.IsObject) { + throw new InstantiationException ("Expected JSON object, found " + node.Tag); + } + ConstructorInfo[] constructors = targetType.GetConstructors ( BindingFlags.Instance | BindingFlags.Public | @@ -302,12 +325,12 @@ private InstantiationData _InstantiateWithConstructor ( foreach (ConstructorInfo constructorInfo in constructors) { var constructorAttribute = Util.GetAttribute (constructorInfo); if (constructorAttribute != null) { - return _InstantiateWithConstructor (node, constructorInfo, deserializer); + return _InstantiateWithConstructor (node, constructorInfo, deserializer, useTupleFormat); } } try { - InstantiationData instantiationData = new InstantiationData(); + InstantiationData instantiationData = new InstantiationData (); instantiationData.instantiatedObject = Activator.CreateInstance (targetType); instantiationData.needsDeserialization = node.Count != 0; return instantiationData; @@ -320,7 +343,8 @@ private InstantiationData _InstantiateWithConstructor ( private InstantiationData _InstantiateWithConstructor ( JSONNode node, ConstructorInfo constructorInfo, - Deserializer deserializer) + Deserializer deserializer, + bool useTupleFormat) { ParameterInfo[] parameters = constructorInfo.GetParameters (); object[] parameterValues = new object[parameters.Length]; @@ -332,23 +356,27 @@ private InstantiationData _InstantiateWithConstructor ( string key = nodeAttribute != null && nodeAttribute.key != null ? nodeAttribute.key : parameters [i].Name; + JSONNode parameterNode = useTupleFormat ? node [i] : node [key]; + ObjectTypes restrictedTypes = restrictAttribute == null ? ObjectTypes.JSON : restrictAttribute.types; Type[] customTypes = restrictAttribute == null ? null : restrictAttribute.customTypes; parameterValues [i] = deserializer.Deserialize ( - node [key], + parameterNode, parameters [i].ParameterType, nodeAttribute == null ? NodeOptions.Default : nodeAttribute.options, restrictedTypes, customTypes); - ignoredKeys.Add (key); + if (!useTupleFormat) { + ignoredKeys.Add (key); + } } - InstantiationData instantiationData = new InstantiationData(); + InstantiationData instantiationData = new InstantiationData (); instantiationData.instantiatedObject = constructorInfo.Invoke (parameterValues); - instantiationData.needsDeserialization = ignoredKeys.Count != node.Count; + instantiationData.needsDeserialization = !useTupleFormat && ignoredKeys.Count != node.Count; instantiationData.ignoredKeys = ignoredKeys; return instantiationData; } diff --git a/Assets/Plugins/UnityJSON/JSON.cs b/Assets/Plugins/UnityJSON/JSON.cs index 8605035..44c1fd8 100644 --- a/Assets/Plugins/UnityJSON/JSON.cs +++ b/Assets/Plugins/UnityJSON/JSON.cs @@ -30,6 +30,26 @@ public static string Serialize ( return serializer.Serialize (obj, options); } + /// + /// Serializes the given object into JSON string. Throws an + /// error if the object is null. + /// + /// Object to be serialized. + /// Custom serializer. Throws an error if + /// null. + public static string Serialize ( + object obj, + Serializer serializer) + { + if (obj == null) { + throw new ArgumentNullException ("obj"); + } + if (serializer == null) { + throw new ArgumentNullException ("serializer"); + } + return serializer.Serialize (obj); + } + /// /// Serializes the object into JSON string. /// @@ -45,6 +65,19 @@ public static string ToJSONString ( return Serialize (obj, options, serializer); } + /// + /// Serializes the object into JSON string. + /// + /// Object to be serialized. + /// Custom serializer. Throws an error if + /// null. + public static string ToJSONString ( + this object obj, + Serializer serializer) + { + return Serialize (obj, serializer); + } + /// /// Deserializes an object of the generic type from /// the given JSON string. Throws an exception if the string @@ -74,6 +107,33 @@ public static T Deserialize ( return (T)deserializer.Deserialize (node, typeof(T), options); } + /// + /// Deserializes an object of the generic type from + /// the given JSON string. Throws an exception if the string + /// is null or not a valid JSON string. + /// + /// The JSON string to deserialize from. + /// Custom deserializer. Throws an error if + /// null. + /// The type of object to deserialize. + public static T Deserialize ( + string jsonString, + Deserializer deserializer) + { + if (jsonString == null) { + throw new ArgumentNullException ("jsonString"); + } + if (deserializer == null) { + throw new ArgumentNullException ("deserializer"); + } + + SimpleJSON.JSONNode node = SimpleJSON.JSON.Parse (jsonString); + if (node == null) { + throw new ArgumentException ("Argument is not a valid JSON string: " + jsonString); + } + return (T)deserializer.Deserialize (node, typeof(T)); + } + /// /// Deserializes a JSON string on a previously existing object. /// Throws an exception if the string is null or not a valid JSON string. @@ -106,6 +166,36 @@ public static void DeserializeOn ( deserializer.DeserializeOn (obj, node, options); } + /// + /// Deserializes a JSON string on a previously existing object. + /// Throws an exception if the string is null or not a valid JSON string. + /// + /// Object to deserialize on. + /// The JSON string to deserialize from. + /// Custom deserializer. Throws an error if + /// null. + public static void DeserializeOn ( + object obj, + string jsonString, + Deserializer deserializer) + { + if (obj == null) { + throw new ArgumentNullException ("obj"); + } + if (jsonString == null) { + throw new ArgumentNullException ("jsonString"); + } + if (deserializer == null) { + throw new ArgumentNullException ("deserializer"); + } + + SimpleJSON.JSONNode node = SimpleJSON.JSON.Parse (jsonString); + if (node == null) { + throw new ArgumentException ("Argument is not a valid JSON string: " + jsonString); + } + deserializer.DeserializeOn (obj, node); + } + /// /// Deserializes a JSON string on the previously existing object. /// Throws an exception if the string is null or not a valid JSON string. @@ -123,5 +213,21 @@ public static void FeedJSON ( { DeserializeOn (obj, jsonString, options, deserializer); } + + /// + /// Deserializes a JSON string on the previously existing object. + /// Throws an exception if the string is null or not a valid JSON string. + /// + /// Object to deserialize on. + /// The JSON string to deserialize from. + /// Custom deserializer. Throws an error if + /// null. + public static void FeedJSON ( + this object obj, + string jsonString, + Deserializer deserializer) + { + DeserializeOn (obj, jsonString, deserializer); + } } } diff --git a/Assets/Plugins/UnityJSON/Serializer.cs b/Assets/Plugins/UnityJSON/Serializer.cs index fd4a286..8966a84 100644 --- a/Assets/Plugins/UnityJSON/Serializer.cs +++ b/Assets/Plugins/UnityJSON/Serializer.cs @@ -18,7 +18,7 @@ public class Serializer private const string _kTrue = "true"; private const string _kFalse = "false"; - private static Serializer _default = new Serializer(); + private static Serializer _default = new Serializer (); /// /// The default serializer to be used when no serializer is given. @@ -46,7 +46,7 @@ public static Serializer Default { /// public bool useUndefinedForNull = false; - private Serializer () + protected Serializer () { } @@ -278,13 +278,19 @@ public string SerializeBounds (Bounds bounds) /// /// Serializes an object by its fields and properties. This will /// ignore custom serializations of the object (see Serializer.TrySerialize - /// and ISerializable.Serialize). + /// and ISerializable.Serialize). This will throw an argument exception if + /// the object is a non-struct value type (primitives and enums). /// public string SerializeByParts (object obj, NodeOptions options = NodeOptions.Default) { if (obj == null) { return SerializeNull (options); } + Type type = obj.GetType (); + if (type.IsPrimitive || type.IsEnum) { + throw new ArgumentException ("Cannot serialize non-struct value types by parts."); + } + return _SerializeCustom (obj, options); } @@ -382,29 +388,35 @@ private string _SerializeCustom (object obj, NodeOptions options) }; Type type = obj.GetType (); - JSONObjectAttribute classAttribute = Util.GetAttribute (type); + JSONObjectAttribute objectAttribute = Util.GetAttribute (type); var flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance; - if (classAttribute != null && !classAttribute.options.ShouldIgnoreStatic ()) { - flags |= BindingFlags.Static; + bool useTupleFormat = false; + if (objectAttribute != null) { + if (!objectAttribute.options.ShouldIgnoreStatic ()) { + flags |= BindingFlags.Static; + } + if (objectAttribute.options.ShouldUseTupleFormat ()) { + useTupleFormat = true; + } } enumerable = enumerable.Concat ( from f in type.GetFields (flags) where isNotExtras (f) && _IsValidFieldInfo (f) - select _SerializeCustomField (obj, f)); + select _SerializeCustomField (obj, f, useTupleFormat)); - if (classAttribute == null || !classAttribute.options.ShouldIgnoreProperties ()) { + if (objectAttribute == null || !objectAttribute.options.ShouldIgnoreProperties ()) { enumerable = enumerable.Concat ( from p in type.GetProperties (flags) where isNotExtras (p) && _IsValidPropertyInfo (p) - select _SerializeCustomProperty (obj, p)); + select _SerializeCustomProperty (obj, p, useTupleFormat)); } // Serialize all properties and fields. var result = _Join (enumerable, o => o as string); // Serialize the extras if there are any. - if (extrasMember != null) { + if (!useTupleFormat && extrasMember != null) { var extras = Util.GetMemberValue (extrasMember, obj) as IEnumerable; if (extras != null) { result += (result == "" ? "" : ",") @@ -415,8 +427,12 @@ where isNotExtras (p) && _IsValidPropertyInfo (p) if (listener != null) { listener.OnSerializationSucceeded (this); } - return "{" + result + "}"; - ; + + if (useTupleFormat) { + return "[" + result + "]"; + } else { + return "{" + result + "}"; + } } catch (Exception exception) { if (listener != null) { listener.OnSerializationFailed (this); @@ -471,17 +487,17 @@ private string _Join (IEnumerable enumerable, Func serializer) return result; } - private string _SerializeCustomField (object obj, FieldInfo fieldInfo) + private string _SerializeCustomField (object obj, FieldInfo fieldInfo, bool useTupleFormat) { - return _SerializeCustomMember (fieldInfo, fieldInfo.GetValue (obj)); + return _SerializeCustomMember (fieldInfo, fieldInfo.GetValue (obj), useTupleFormat); } - private string _SerializeCustomProperty (object obj, PropertyInfo propertyInfo) + private string _SerializeCustomProperty (object obj, PropertyInfo propertyInfo, bool useTupleFormat) { - return _SerializeCustomMember (propertyInfo, propertyInfo.GetValue (obj, null)); + return _SerializeCustomMember (propertyInfo, propertyInfo.GetValue (obj, null), useTupleFormat); } - private string _SerializeCustomMember (MemberInfo keyMemberInfo, object value) + private string _SerializeCustomMember (MemberInfo keyMemberInfo, object value, bool useTupleFormat) { JSONNodeAttribute attribute = Util.GetAttribute (keyMemberInfo); NodeOptions options = attribute == null ? NodeOptions.Default : attribute.options; @@ -491,6 +507,9 @@ private string _SerializeCustomMember (MemberInfo keyMemberInfo, object value) string valueString = Serialize (value, options); if (valueString != null || options.ShouldSerializeNull ()) { + if (useTupleFormat) { + return valueString == null ? _kUndefined : valueString; + } string key = (attribute != null && attribute.key != null) ? attribute.key : keyMemberInfo.Name; return _SerializeString (key) + ":" + (valueString == null ? _kUndefined : valueString); } else { diff --git a/README.md b/README.md index cbbf015..d7be595 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,6 @@ * [Features](#features) * [Installation](#installation) * [Serialization](#serialization) - - [Enums](#enums) - [Serialization Lifecycle](#serialization-lifecycle) - [Custom Serialization with Serializer](#custom-serialization-with-serializer) - [Custom Serialization with ISerializable](#custom-serialization-with-iserializable) @@ -20,6 +19,9 @@ - [Custom Deserialization with Instantiater](#custom-deserialization-with-instantiater) - [Custom Deserialization with Deserializer](#custom-deserialization-with-deserializer) - [Custom Deserialization with IDeserializable](#custom-deserialization-with-ideserializable) +* [Special Types](#special-types) + - [Enums](#enums) + - [Tuples](#tuples) * [Changelog](#changelog) - [v2.0](#v20) - [v1.1](#v11) @@ -125,28 +127,8 @@ at. It uses the `ObjectOptions` enum which has the following serialization optio - IgnoreProperties: Ignores all properties from serialization / deserialization. - IncludeStatic: Includes static fields and properties in serialization / deserialization. - -### Enums - -Enums are by default serialized directly with their member names. Their serialization -can, however, be customized with the use of `JSONEnumAttribute`. The attribute allows the -following formating options: - -- useIntegers: The enums are serialized / deserialized according to their numeric values. -- format: Optional formatting to be applied given in the form of `JSONEnumMemberFormating`. -It supports lowercase, uppercase or captialize (only the first letter is captialized). -- prefix: Adds an optional prefix to the formatted member name. -- suffix: Adds an optional suffix to the formatted member name. - -```cs -[JSONEnum(format = JSONEnumMemberFormating.Lowercased, suffix = "Position")] -public enum Positions -{ - Forward -} - -JSON.Serialize(Positions.Forward) // forwardPosition -``` +- TupleFormat: Handles the struct or the class as a tuple of fields. See [Tuples](#tuples) +for more detail. ### Serialization Lifecycle @@ -643,19 +625,87 @@ public class AClass : IDeserializable The classes that are deserialized with the `IDeserializable.Deserialize` method do not receive deserialization lifecycle calls from `IDeserializationListener`. +## Special Types + +### Enums + +Enums are by default serialized and deserialized directly with their member names. This process +can, however, be customized with the use of `JSONEnumAttribute`. The attribute allows the +following formating options: + +- useIntegers: The enums are serialized / deserialized according to their numeric values. +- format: Optional formatting to be applied given in the form of `JSONEnumMemberFormating`. +It supports lowercase, uppercase or captialize (only the first letter is captialized). +- prefix: Adds an optional prefix to the formatted member name. +- suffix: Adds an optional suffix to the formatted member name. + +```cs +[JSONEnum(format = JSONEnumMemberFormating.Lowercased, suffix = "Position")] +public enum Positions +{ + Forward +} + +JSON.Serialize(Positions.Forward) // forwardPosition +JSON.DeserializeEnum("forwardPosition") // Positions.Forward +``` + +### Tuples + +Classes and structs can also be serialized and deserialized as tuples (JSON arrays). This +is performed by adding the `ObjectOptions.TupleFormat` to a `JSONObjectAttribute` at +the class / struct declaration. Tuple formatted classes and structs always ignore properties. +When serialized, the fields are serialized in an array in the order they are declared. +When deserialized, the class / struct MUST provide a constructor with the +`JSONConstructorAttribute` where the arguments are passed directly from the array. + +```cs +[JSONObject(ObjectOptions.TupleFormat)] +public class Tuple +{ + [JSONNode(NodeOptions.SerializeNull)] + public T1 item1; + + [JSONNode(NodeOptions.SerializeNull)] + public T2 item2; + + [JSONConstructor] + public Tuple(T1 item1, T2 item2) + { + this.item1 = item1; + this.item2 = item2; + } +} + +var tuple = new Tuple(2, "value"); +tuple.ToJSONString(); // [2, "value"] + +var obj = JSON.Deserialize>>( + "[[\"this\",\"is\",\"IList\"], [3.14, 2.17]]"); +``` + +Please notice that tuple deserialization takes place at the instantiation and therefore +cannot be used together with `Deserializer.DeserializeOn`. + +UnityJSON does not use C# tuples because Unity3D does not have support for them yet. + ## Changelog +### v2.1 + +- Provides Tuple support + ### v2.0 - Bug fixes -- Added Serializer.SerializeByParts -- Added Deserializer.DeserializeByParts and deserializer methods taking JSON +- Adds Serializer.SerializeByParts +- Adds Deserializer.DeserializeByParts and deserializer methods taking JSON string arguments -- Created the class Instantiater +- Creates the class Instantiater - Allows use of RestrictTypeAttribute with constructor arguments - Introduces InstantiationData to work around ignored keys ### v1.1 -- Added `JSONConstructorAttribute` -- Fixed conditional instantiation bug: JSONNode kept the same after key removal +- Adds `JSONConstructorAttribute` +- Fixes conditional instantiation bug: JSONNode kept the same after key removal diff --git a/unityjson.unitypackage b/unityjson.unitypackage index aecfe476a79b49e09f9dfe671482fdf30b6d8fd3..57950d78ed8622dea0c8edcd088b3930fef1f5bd 100644 GIT binary patch delta 26922 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 delta 26163 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