static object DeserializeToCSharpObject_Object_WithRecursion(IEnumerable <XNode> content, Type resultType, XElement parentElement, IReadOnlyList <Type> knownTypes, bool ignoreErrors, bool useXmlSerializerFormat)
        {
            // Quit if attempting to deserialize to an interface: //todo: investigate why this may happen.
            if (!resultType.IsInterface)
            {
                string resultTypeFullName = resultType.FullName; // For debugging only, can be removed.

                // Create the resulting class:
                object resultInstance = Activator.CreateInstance(resultType); //todo: replace with "System.Runtime.Serialization.FormatterServices.GetUninitializedObject(type)" so that the type does not require a parameterless constructor.

                // Call the "OnDeserializing" method if any:
                CallOnDeserializingMethod(resultInstance, resultType);

                // Get the type information (namespace, etc.) by reading the DataContractAttribute and similar attributes, if present:
                TypeInformation typeInformation = DataContractSerializer_Helpers.GetTypeInformationByReadingAttributes(resultType, null);

                // Read the members of the target type:
                IEnumerable <MemberInformation> membersInformation = DataContractSerializer_Helpers.GetDataContractMembers(resultType, typeInformation.serializationType, useXmlSerializerFormat);

                // Make a dictionary of the members of the target type for faster lookup:
                Dictionary <string, MemberInformation> memberNameToMemberInformation = new Dictionary <string, MemberInformation>();
                foreach (var memberInformation in membersInformation)
                {
                    string memberName = memberInformation.Name;
                    if (resultType.FullName.StartsWith("System.Collections.Generic.KeyValuePair"))
                    {
                        if (memberName == "key")
                        {
                            memberName = "Key";
                        }
                        else if (memberName == "value")
                        {
                            memberName = "Value";
                        }
                    }
                    if (!memberNameToMemberInformation.ContainsKey(memberName))
                    {
                        memberNameToMemberInformation.Add(memberName, memberInformation);
                    }
                    else
                    {
                        MemberInformation collidingMemberInformation = memberNameToMemberInformation[memberName];
                        throw new InvalidDataContractException(
                                  string.Format(
                                      "Type '{0}' contains two members '{1}' 'and '{2}' with the same data member name '{3}'. Multiple members with the same name in one type are not supported. Consider changing one of the member names using DataMemberAttribute attribute.",
                                      resultType.ToString(),
                                      memberInformation.MemberInfo.Name,
                                      collidingMemberInformation.MemberInfo.Name,
                                      memberName
                                      ));
                    }
                }

                // Populate the values of the properties/members of the class:
                HashSet2 <string> membersForWhichWeSuccessfullSetTheValue = new HashSet2 <string>();
                foreach (XNode node in content)
                {
                    if (node is XElement) // Normally an object property was serialized as an XElement.
                    {
                        XElement xElement    = (XElement)node;
                        XName    elementName = xElement.Name;
                        string   elementNameWithoutNamespace = elementName.LocalName;

                        // Find the member that has the name of the XNode:
                        MemberInformation memberInformation;
                        if (memberNameToMemberInformation.TryGetValue(elementNameWithoutNamespace, out memberInformation))
                        {
                            // Avoid processing nodes that have the same name as other nodes already processed (this can happen in case of [XmlElement] attribute on enumerable members - cf. "special case" below - but it is handled differently):
                            if (!membersForWhichWeSuccessfullSetTheValue.Contains(memberInformation.Name))
                            {
                                object memberValue      = null;
                                Type   memberActualType = memberInformation.MemberType; // Note: this is the initial value. It may be modified below.
                                if (DataContractSerializer_Helpers.IsElementNil(xElement))
                                {
                                    //----------------------
                                    // XNode is "Nil", so we return the default value of the result type
                                    //----------------------

                                    memberValue = DataContractSerializer_Helpers.GetDefault(memberInformation.MemberType);
                                }
                                else
                                {
                                    bool isNull = false;

                                    //foreach (XAttribute attribute in xElement.Attributes(XNamespace.Get("http://www.w3.org/2001/XMLSchema-instance").GetName("nil"))) //doesn't work...
                                    //todo: try removing this foreach since it should be handled in the "if(IsElementDefaut(xElement))" above.
                                    foreach (XAttribute attribute in xElement.Attributes("nil")) //We have to do this here because those usually do not have nodes, which causes problems when doing the recursion.
                                    {
                                        isNull = Convert.ToBoolean(attribute.Value);
                                        if (isNull)
                                        {
                                            memberValue = null;
                                        }
                                    }

                                    if (!isNull)
                                    {
                                        memberActualType = DataContractSerializer_KnownTypes.GetCSharpTypeForNode(xElement, memberInformation.MemberInfo.DeclaringType, memberActualType, knownTypes, memberInformation);

                                        //if the type is nullable, we get the undelying type:
                                        Type nonNullableMemberType = memberActualType;
                                        if (memberActualType.FullName.StartsWith("System.Nullable`1"))
                                        {
                                            nonNullableMemberType = Nullable.GetUnderlyingType(memberActualType);
                                        }

                                        // Recursively create the value for the property:
                                        IEnumerable <XNode> propertyChildNodes = xElement.Nodes();

                                        //********** RECURSION **********
                                        memberValue = DeserializeToCSharpObject(propertyChildNodes, nonNullableMemberType, xElement, knownTypes, ignoreErrors, useXmlSerializerFormat);
                                    }

                                    //---------------------------------
                                    // Handle the special case where there is an [XmlElement] attribute on an enumerable member (XmlSerializer compatibility mode only):
                                    //
                                    // Example:
                                    //      <MyObject>
                                    //         <MyEnumerablePropertyName/>
                                    //         <MyEnumerablePropertyName/>
                                    //         <MyEnumerablePropertyName/>
                                    //      </MyObject>
                                    //
                                    // obtained via:
                                    //      class MyObject
                                    //      {
                                    //          [XmlElement]
                                    //          List<MyType> MyEnumerablePropertyName { get; set; }
                                    //      }
                                    //
                                    // cf. https://docs.microsoft.com/en-us/dotnet/standard/serialization/controlling-xml-serialization-using-attributes
                                    //---------------------------------
                                    Type itemsType = null;
                                    bool specialCaseWhereAnEnumerableHasTheXmlElementAttribute =
                                        (useXmlSerializerFormat &&
                                         memberInformation.HasXmlElementAttribute &&
                                         DataContractSerializer_Helpers.IsAssignableToGenericEnumerableOrArray(memberActualType, out itemsType));
                                    if (specialCaseWhereAnEnumerableHasTheXmlElementAttribute)
                                    {
                                        object deserializedEnumerable = DeserializeToCSharpObject_Enumerable_WithRecursion_SpecialCase(
                                            memberInformation.Name,
                                            content, memberActualType, knownTypes, ignoreErrors, itemsType, useXmlSerializerFormat);
                                        memberValue = deserializedEnumerable;
                                    }

                                    //---------------------------------
                                    // Set the value of the member:
                                    //---------------------------------

                                    DataContractSerializer_Helpers.SetMemberValue(resultInstance, memberInformation, memberValue);
                                    membersForWhichWeSuccessfullSetTheValue.Add(memberInformation.Name);
                                }
                            }
                        }
                        else
                        {
                            //-----------
                            // We ignore missing members, to mimic the behavior of the .NET DataContractSerializer.
                            //-----------
                            //throw new Exception("Member '" + memberName + "' not found in type '" + resultType.Name + "'.");
                        }
                    }
                }

                // In case of XmlSerializer compatibility mode, and [XmlAttribute] attribute on a class member, we also need to deserialize the XAttributes (cf. https://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlattributeattribute(v=vs.110).aspx ):
                if (useXmlSerializerFormat)
                {
                    foreach (XAttribute attribute in parentElement.Attributes())
                    {
                        XName attributeName = attribute.Name;
                        // We assume that the object properties have no namespace //todo: fix this assumption, cf. "XmlAttributeAttribute.Namespace" for example (note: repetition of "Attribute" is intended)
                        if (string.IsNullOrEmpty(attributeName.NamespaceName))
                        {
                            string attributeNameWithoutNamespace = attributeName.LocalName;

                            // Find the member that has the name of the XAttribute:
                            MemberInformation memberInformation;
                            if (memberNameToMemberInformation.TryGetValue(attributeNameWithoutNamespace, out memberInformation) &&
                                memberInformation.HasXmlAttributeAttribute)
                            {
                                // Avoid processing members that have already been processed (just in case):
                                if (!membersForWhichWeSuccessfullSetTheValue.Contains(memberInformation.Name))
                                {
                                    string attributeValue = attribute.Value;

                                    // Check to see if the expected type is a value type:
                                    if (DataContractSerializer_ValueTypesHandler.TypesToNames.ContainsKey(memberInformation.MemberType))
                                    {
                                        // Attempt to deserialize the string:
                                        object memberValue = DataContractSerializer_ValueTypesHandler.ConvertStringToValueType(attributeValue, memberInformation.MemberType);

                                        // Set the value of the member:
                                        DataContractSerializer_Helpers.SetMemberValue(resultInstance, memberInformation, memberValue);
                                        membersForWhichWeSuccessfullSetTheValue.Add(memberInformation.Name);
                                    }
                                    else
                                    {
                                        //todo: report the error?
                                        if (memberInformation.MemberType == typeof(List <int>))
                                        {
                                            string[] splittedElements = attributeValue.Split(' ');

#if !BRIDGE
                                            List <int> listint = splittedElements.Select(Int32.Parse).ToList();
#else
                                            List <int> listint = new List <int>();

                                            foreach (string str in splittedElements)
                                            {
                                                listint.Add(Int32.Parse(str));
                                            }
#endif


                                            DataContractSerializer_Helpers.SetMemberValue(resultInstance, memberInformation, listint);
                                            membersForWhichWeSuccessfullSetTheValue.Add(memberInformation.Name);
                                        }
                                    }
                                }
                                else
                                {
                                    //todo: report the error?
                                }
                            }
                            else
                            {
                                //todo: report the error?
                            }
                        }
                    }
                }

                // Verify that the values of all the members marked as "IsRequired" have been set:
                foreach (var memberInformation in membersInformation)
                {
                    if (memberInformation.IsRequired &&
                        !membersForWhichWeSuccessfullSetTheValue.Contains(memberInformation.Name))
                    {
                        throw new SerializationException(string.Format("The member '{0}' is required but it was not found in the document being deserialized.", memberInformation.Name));
                    }
                }

                // Call the "OnDeserialized" method if any:
                CallOnDeserializedMethod(resultInstance, resultType);

                return(resultInstance);
            }
            else
            {
                return(null);
            }
        }
        static object DeserializeToCSharpObject_Enumerable_WithRecursion(IEnumerable <XNode> content, Type resultType, IReadOnlyList <Type> knownTypes, bool ignoreErrors, Type itemsType, bool useXmlSerializerFormat)
        {
            // Here is how it works:
            // 1. First we create a new instance of List<T> to add child items recursively
            // 2. Then:
            //   - if the result type is an array or just "IEnumerable", we convert the list to an array and return it
            //   - if the result type is List<T> or a compatible interface such as IList<> ,IEnumerable<>, ICollection<>, IReadOnlyCollection<>, IReadOnlyList<>, we just return the list "as is".
            //   - otherwise we attempt to create a new instance of the result type by passing the list to the constructor and return it
            //   - if it fails (because no such constructor exists), we attempt to create a new instance and call the "Add(T)" method to add the items, if found, and return the new instance.


            //--------------------------------
            // Create a temporary List<T> in order to add items to it. Later we will convert it to the final type if needed.
            //--------------------------------

#if !BRIDGE
            var methodToCreateNewInstanceOfGenericList = typeof(DataContractSerializer_Deserialization).GetMethod("CreateNewInstanceOfGenericList", BindingFlags.NonPublic | BindingFlags.Static);
            if (methodToCreateNewInstanceOfGenericList == null)
            {
                throw new Exception("Cannot find the private static method named 'CreateNewInstanceOfGenericList'.");
            }
            object list = methodToCreateNewInstanceOfGenericList.MakeGenericMethod(itemsType).Invoke(null, new object[] { });

            // Note: in the code above, we call the method "CreateNewInstanceOfGenericList" instead of
            // calling "var list = Activator.CreateInstance(typeof(List<>).MakeGenericType(itemsType))"
            // because the latter does not appear to properly initialize the underlying JavaScript "_items"
            // collection that is inside the List<T> implementation in JSIL as of July 14, 2017, thus
            // resulting in an exception when calling the Add method (reference: CSHTML5 tickets #623 and
            // #648).
#else
            // TODOBRIDGE: verify if the two code are similar
            Type[] arg = { itemsType };
            object list;

            if (Interop.IsRunningInTheSimulator)
            {
                list = INTERNAL_Simulator.SimulatorProxy.MakeInstanceOfGenericType(typeof(List <>), arg);
            }
            else
            {
                list = Activator.CreateInstance(typeof(List <>).MakeGenericType(arg));
            }
#endif


            // Get a reference to the "Add" method of the generic list that we just created:
            var listAddMethod = list.GetType().GetMethod("Add");

            int count = 0; // Note: this is for the case where we have an array, to be able to create an array of the correct size.

            //--------------------------------
            // Add the items to the list:
            //--------------------------------
            foreach (XNode node in content)
            {
                if (node is XElement) // Normally the elements of a IEnumerable were serialized as XElements
                {
                    XElement xElement = (XElement)node;
                    object   childObject;
                    if (DataContractSerializer_Helpers.IsElementNil(xElement))
                    {
                        if (itemsType.IsValueType && !itemsType.FullName.StartsWith("System.Nullable`1"))
                        {
                            childObject = Activator.CreateInstance(itemsType);
                        }
                        else
                        {
                            childObject = null;
                        }
                    }
                    else
                    {
                        IEnumerable <XNode> elementChildNodes = xElement.Nodes();

                        Type childObjectActualType = DataContractSerializer_KnownTypes.GetCSharpTypeForNode(xElement, itemsType, itemsType, knownTypes, null); //Note: the two "null" values are used only in the case where we couldn't find the type.


                        //********** RECURSION **********
                        childObject = DeserializeToCSharpObject(elementChildNodes, childObjectActualType, xElement, knownTypes, ignoreErrors, useXmlSerializerFormat);
                    }

                    // Add the child to the resulting enumerable:
                    listAddMethod.Invoke(list, new object[] { childObject });
                }
                ++count;
            }

            //--------------------------------
            // Convert the list to the result type:
            //--------------------------------

            Type genericTypeDefinition;
            if (resultType.IsArray || resultType == typeof(IEnumerable)) // Note: here we deliberately use "==" instead of "IsAssignableFrom".
            {
                //------------------------
                // If the result type is an array T[] or the type is exactly "IEnumerable"
                //------------------------

                //create an array with the correct number of elements:
                Array result = Array.CreateInstance(itemsType, count);

                //now we need to fill the array:
                ((IList)list).CopyTo(result, 0);

                return(result);
            }
            else if (resultType.IsGenericType &&
                     (genericTypeDefinition = resultType.GetGenericTypeDefinition()) != null &&
                     (genericTypeDefinition == typeof(List <>) ||
                      genericTypeDefinition == typeof(IList <>) ||
                      genericTypeDefinition == typeof(IEnumerable <>) ||
                      genericTypeDefinition == typeof(ICollection <>)
                      //|| genericTypeDefinition == typeof(IReadOnlyCollection<>)
                      //|| genericTypeDefinition == typeof(IReadOnlyList<>)
                     ))
            {
                //------------------------
                // If the result type is List<T> or a compatible interface such as: IList<> ,IEnumerable<>, ICollection<>, IReadOnlyCollection<>, IReadOnlyList<>
                //------------------------

                // We directly return the List<> that we created above:
                return(list);
            }
            else
            {
                //------------------------
                // Otherwise, we attempt to create a new instance of the result type by passing the items as first argument of the constructor (this works for example with ObservableCollection<T> and other common collections):
                //------------------------

                try
                {
                    //todo: check if the type inherits from Dictionary here and if so, we do nothing here and it will be handled later.
#if !BRIDGE
                    object result1 = Activator.CreateInstance(resultType, args: new object[] { list });
#else
                    object result1 = Activator.CreateInstance(resultType, arguments: new object[] { list });
#endif


                    //we check if the elements have correctly been added to the result. If they have, we return the result, otherwise, we try to add the elements through a Add method.
                    //result1 is an IEnumerable<> or an Array
                    bool isOk = false;
                    if (count == 0) //if there was no elements to add anyway, the result is good as it is.
                    {
                        isOk = true;
                    }
                    else
                    {
                        if (resultType.IsArray)
                        {
                            if (((Array)result1).Length == count)
                            {
                                isOk = true;
                            }
                        }
                        else //result1 is an IEnumerable<>
                        {
                            foreach (object item in (IEnumerable)result1)
                            {
                                isOk = true;
                                break;//if there is at least one element, we assume all elements were added correctly.
                            }
                        }
                    }
                    if (isOk)
                    {
                        return(result1);
                    }
                }
                catch
                {
                    // If it failed, we attempt something else (see below).
                }

                //------------------------
                // Otherwise, we search for the method "Add(T)" in the result type, so that we can create a new instance of the type and then we call "Add(T)" to add the items:
                //------------------------

                // Get a reference to the "Add(T)" method:
                var  addMethod    = resultType.GetMethod("Add", new Type[] { itemsType });
                bool isDictionary = false;
                if (addMethod == null)
                {
                    //if we couldn't find an Add method, we check if it is a Dictionary, and if so we call the Add(Key, Value) method instead:

                    //note: Another way to try and make it work could be to look if itemsType is a GenericType and try to find the elements of the types in its genericArguments and find a Add ethod with those arguments types?

                    Type currentType = resultType;
                    while (currentType != null && !(currentType.FullName.StartsWith("System.Collections.Generic.Dictionary"))) //this isn't great but I couldn't find a better way at the moment.
                    {
                        currentType = currentType.BaseType;
                    }
                    if (currentType != null)
                    {
                        currentType = itemsType;
                        while (currentType != null && !(currentType.FullName.StartsWith("System.Collections.Generic.KeyValuePair"))) //this isn't great but I couldn't find a better way at the moment.
                        {
                            currentType = currentType.BaseType;
                        }

                        if (currentType != null)
                        {
                            isDictionary = true;
                            Type keyType   = itemsType.GetGenericArguments()[0];
                            Type valueType = itemsType.GetGenericArguments()[1];
                            addMethod = resultType.GetMethod("Add", new Type[] { keyType, valueType });
                        }
                    }
                    if (!isDictionary)
                    {
                        if (!ignoreErrors)
                        {
                            throw new InvalidDataContractException(
                                      string.Format(
                                          "Type '{0}' is an invalid collection type since it does not have a valid Add method with parameter of type '{1}'.",
                                          resultType.ToString(),
                                          itemsType.ToString()
                                          ));
                        }
                        else
                        {
                            return(null);
                        }
                    }
                }

                // Create a new instance of the result type:
                object result2 = null;
                try
                {
                    result2 = Activator.CreateInstance(resultType); //todo: support creating the object without calling the constructor? (in that case, make sure to change the message of the exception in case of failure)
                }
                catch
                {
                }
                if (result2 == null)
                {
                    if (!ignoreErrors)
                    {
                        throw new SerializationException(
                                  string.Format(
                                      "Cannot create a new instance of the type '{0}'. Please verify that the type has a public parameterless constructor.",
                                      resultType.ToString()
                                      ));
                    }
                    else
                    {
                        return(null);
                    }
                }

                // Add the items to the collection:
                if (!isDictionary)
                {
                    foreach (var item in (IList)list)
                    {
                        addMethod.Invoke(result2, new object[] { item });
                    }
                }
                else
                {
                    foreach (var item in (IList)list)
                    {
                        dynamic dynamicItem = item;// using a dynamic here since it it much simpler but if it causes issues, we should use reflection to get Key and Value.
                        addMethod.Invoke(result2, new object[] { dynamicItem.Key, dynamicItem.Value });
                    }
                }

                return(result2);
            }
        }