public object DeserializeFromXElement(XElement xElement)
        {
            Type   expectedType         = this._type;
            Type   actuallyExpectedType = DataContractSerializer_KnownTypes.GetCSharpTypeForNode(xElement, this._type, expectedType, _knownTypes, null, _useXmlSerializerFormat);
            object result = DataContractSerializer_Deserialization.DeserializeToCSharpObject(xElement.Nodes(), actuallyExpectedType, xElement, _knownTypes, ignoreErrors: false, useXmlSerializerFormat: _useXmlSerializerFormat);

            return(result);
        }
        public object DeserializeFromString(string xml)
        {
            XDocument xdoc                 = XDocument.Parse(xml);
            XElement  root                 = xdoc.Root;
            Type      expectedType         = this._type;
            Type      actuallyExpectedType = DataContractSerializer_KnownTypes.GetCSharpTypeForNode(root, this._type, expectedType, _knownTypes, null, _useXmlSerializerFormat);
            object    result               = DataContractSerializer_Deserialization.DeserializeToCSharpObject(root.Nodes(), actuallyExpectedType, root, _knownTypes, ignoreErrors: false, useXmlSerializerFormat: _useXmlSerializerFormat);

            return(result);
        }
Esempio n. 3
0
        static List <XNode> SerializeToXNodes_Object_WithRecursion(object obj, Type objectType, Type resultExpectedType, IReadOnlyList <Type> knownTypes, bool useXmlSerializerFormat, string nodeDefaultNamespaceIfAny, bool isRoot, bool isContainedInsideEnumerable, TypeInformation parentTypeInformation)
        {
            // Call the "OnSerializing" method if any:
            CallOnSerializingMethod(obj, objectType);

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

            // Process each member of the object:
            List <XNode> childrenNodes = new List <XNode>();
            IEnumerable <MemberInformationAndValue> membersAndValues = DataContractSerializer_Helpers.GetDataContractMembersAndValues(obj, serializationType: typeInformation.serializationType, useXmlSerializerFormat: useXmlSerializerFormat); //todo: normally, checking if a data contract is present is not enough to know if the type if "marked with attributes". According to the MSND article "Using Data Contracts", we should check for any of the following attributes: "DataContractAttribute, SerializableAttribute, CollectionDataContractAttribute, or EnumMemberAttribute attributes, or marked as serializable by any other means (such as IXmlSerializable)". cf. https://msdn.microsoft.com/en-us/library/ms733127(v=vs.100).aspx

            foreach (MemberInformationAndValue memberInfoAndValue in membersAndValues)
            {
                //------------------------------------
                // Process each member of the object
                //------------------------------------

                // Get the member information:
                MemberInfo memberInfo  = memberInfoAndValue.MemberInformation.MemberInfo;
                object     memberValue = memberInfoAndValue.MemberValue;
                string     memberName  = memberInfoAndValue.MemberInformation.Name;

                // Create the XNode for the member:
                XName xnameForMember;
                if (objectType.FullName.StartsWith("System.Collections.Generic.KeyValuePair"))
                {
                    if (memberName == "key")
                    {
                        memberName = "Key";
                    }
                    else if (memberName == "value")
                    {
                        memberName = "Value";
                    }
                    xnameForMember = memberName;
                }
                else
                {
                    if (typeInformation.NamespaceName == null) //todo: make sure we want to use this typeInformation since it comes from the type that contains of the current member and not the member itself.
                    {
                        xnameForMember = memberName;
                    }
                    else
                    {
                        xnameForMember = XNamespace.Get(typeInformation.NamespaceName).GetName(memberName);
                    }
                }
                XElement xElementForMember = new XElement(xnameForMember);

                bool isNull = ((memberValue == null) || DataContractSerializer_Helpers.CheckIfObjectIsNullNullable(memberValue));

                if (!isNull)
                {
                    Type expectedType = memberInfoAndValue.MemberInformation.MemberType;
                    Type memberType   = memberValue.GetType();

                    // Work around JSIL issues:
                    if (memberValue is char && expectedType == typeof(char)) //Note: this test is required because JSIL thinks that object testobj = 'c'; testobj.GetType() should return System.String...
                    {
                        memberType = typeof(char);
                    }
                    else if (expectedType == typeof(double)) //Note: this test is required because, with JSIL, "GetType" on a double returns "int" instead of "double". //todo: see if other workarounds to JSIL bugs like this one are required.
                    {
                        memberType = typeof(double);
                    }
                    else if (expectedType == typeof(byte)) //same as above.
                    {
                        memberType = typeof(byte);
                    }
                    else if (expectedType == typeof(float)) //same as above.
                    {
                        memberType = typeof(float);
                    }

                    bool isValueEnumerableDifferentThanString = (memberValue is IEnumerable) && !(memberValue is string);

                    Type nonNullableMemberType = memberType;
                    if (memberType.FullName.StartsWith("System.Nullable`1"))
                    {
                        nonNullableMemberType = Nullable.GetUnderlyingType(memberType);
                    }
                    Type nonNullableExpectedType = expectedType;
                    if (expectedType.FullName.StartsWith("System.Nullable`1"))
                    {
                        nonNullableExpectedType = Nullable.GetUnderlyingType(expectedType);
                    }

                    if (nonNullableMemberType != nonNullableExpectedType && !isValueEnumerableDifferentThanString)
                    {
                        //we want to add a type attribute to be able to know when deserializing that this is another type that the property's
                        if (DataContractSerializer_ValueTypesHandler.TypesToNames.ContainsKey(nonNullableMemberType)) //todo: should we add the nullable versions?
                        {
                            string prefixForType = xElementForMember.GetPrefixOfNamespace("http://www.w3.org/2001/XMLSchema");
                            if (string.IsNullOrWhiteSpace(prefixForType))
                            {
                                //we need to create a prefix for that
                                //todo:see if it would be ok to use d2p1 like silverlight seems to do, and if so, replace the following with just that.

                                prefixForType = DataContractSerializer_Helpers.GenerateUniqueNamespacePrefixIfNeeded(xElementForMember, "http://www.w3.org/2001/XMLSchema");

                                //we can finally add the type attribute:
                                xElementForMember.Add(new XAttribute(XNamespace.Get(DataContractSerializer_Helpers.XMLSCHEMA_NAMESPACE).GetName("type"), prefixForType + ":" + DataContractSerializer_ValueTypesHandler.TypesToNames[nonNullableMemberType]));
                            }
                            else
                            {
                                xElementForMember.Add(new XAttribute(XNamespace.Get(DataContractSerializer_Helpers.XMLSCHEMA_NAMESPACE).GetName("type"), prefixForType + ":" + DataContractSerializer_ValueTypesHandler.TypesToNames[nonNullableMemberType]));
                            }
                        }
                        else
                        {
                            bool isTypeOk = DataContractSerializer_KnownTypes.CheckIfItIsAKnownType(obj, objectType, knownTypes, memberType);
                            if (isTypeOk)
                            {
                                if (memberType.IsEnum) //enums are a special case because JSIL is not capable of handling Custom attributes on them.
                                {
                                    xElementForMember.Add(new XAttribute(XNamespace.Get(DataContractSerializer_Helpers.XMLSCHEMA_NAMESPACE).GetName("type"), memberType.Name));
                                }
                                else
                                {
                                    string defaultNamespace = DataContractSerializer_Helpers.DATACONTRACTSERIALIZER_OBJECT_DEFAULT_NAMESPACE + memberType.Namespace;

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

                                    string prefixForTypeName = "";
                                    if (childTypeInformation.NamespaceName != null)                                                                                                            //when the namespaceName is null I guess it means we don't need something like type="sth:ChildTypeName" but type="ChildTypeName" is sufficient.
                                    {
                                        prefixForTypeName = DataContractSerializer_Helpers.GenerateUniqueNamespacePrefixIfNeeded(xElementForMember, childTypeInformation.NamespaceName) + ":"; // note: we added : directly because whenever we have a prefix, we have ':' right after.
                                    }

                                    xElementForMember.Add(new XAttribute(XNamespace.Get(DataContractSerializer_Helpers.XMLSCHEMA_NAMESPACE).GetName("type"), prefixForTypeName + childTypeInformation.Name));
                                }
                            }
                            else
                            {
                                string namespaceNameToPutInException = "";
                                if (typeInformation.NamespaceName != null)
                                {
                                    namespaceNameToPutInException = ":" + typeInformation.NamespaceName;
                                }
                                throw new SerializationException("Type \"" + memberType.FullName + "\" with data contract name \"" + memberType.Name + namespaceNameToPutInException + "\" is not expected. Add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.");
                            }
                        }
                    }

                    //********** RECURSION **********
                    List <XNode> xnodesForMemberValue = SerializeToXNodes(memberValue, memberType, knownTypes, useXmlSerializerFormat, isRoot: false, isContainedInsideEnumerable: false, parentTypeInformation: typeInformation, nodeDefaultNamespaceIfAny: typeInformation.NamespaceName);
                    foreach (XNode xnodeForMemberValue in xnodesForMemberValue) // Note: the collection usually contains only 1 node, but there may be multiple nodes if for example we are serializing an Enumerable.
                    {
                        xElementForMember.Add(xnodeForMemberValue);
                    }
                }
                else
                {
                    //------------------------------------
                    // The value of the member is "null"
                    //------------------------------------

                    XName nilName = XNamespace.Get(DataContractSerializer_Helpers.XMLSCHEMA_NAMESPACE).GetName("nil");
                    xElementForMember.Add(new XAttribute(nilName, "true"));
                }
                childrenNodes.Add(xElementForMember);
            }
            if (isRoot || isContainedInsideEnumerable)
            {
                //we add a XElement with the type name as its name.
                //we create the XName for the node containing the type.

                //----------------------------------
                // Determine the name of the object to use in the XML:
                //----------------------------------

                //we get the type expected by the parent Enumerable:
                Type typeExpectedByParentEnumerable = isRoot ? resultExpectedType : DataContractSerializer_Helpers.GetInterface(parentTypeInformation.Type, "IEnumerable`1").GetGenericArguments()[0];

                string objectTypeName;

                // If the parent of the object is a collection that has the
                // "CollectionDataContractAttribute", we use the name specified
                // by that attribute, if any. Otherwise we determine the name
                // from the Type of the object

                if (parentTypeInformation != null &&
                    !string.IsNullOrEmpty(parentTypeInformation.ItemName))
                {
                    objectTypeName = parentTypeInformation.ItemName;
                }
                else
                {
                    objectTypeName = DataContractSerializer_Helpers.GetTypeNameSafeForSerialization(typeExpectedByParentEnumerable); // Note: in case of nested types, this method replaces the '+' with '.', and does other changes to obtain the type name to use in the serialization.
                }

                XName elementName;
                if (typeInformation.NamespaceName == null)
                {
                    elementName = objectTypeName;
                }
                else
                {
                    elementName = XNamespace.Get(typeInformation.NamespaceName).GetName(objectTypeName);
                }

                XElement xelement = new XElement(elementName);

                if (objectType.IsEnum) //enums are a special case because JSIL is not capable of handling Custom attributes on them.
                {
                    xelement.Add(new XAttribute(XNamespace.Get(DataContractSerializer_Helpers.XMLSCHEMA_NAMESPACE).GetName("type"), objectTypeName));
                }
                else if (typeInformation.NamespaceName != null && !objectType.IsGenericType && typeExpectedByParentEnumerable != obj.GetType())
                {
                    string prefixForTypeName = DataContractSerializer_Helpers.GenerateUniqueNamespacePrefixIfNeeded(xelement, typeInformation.NamespaceName);

                    xelement.Add(new XAttribute(XNamespace.Get(DataContractSerializer_Helpers.XMLSCHEMA_NAMESPACE).GetName("type"), prefixForTypeName + ":" + typeInformation.Name));
                }

                foreach (XNode node in childrenNodes)
                {
                    xelement.Add(node);
                }
                childrenNodes = new List <XNode>()
                {
                    xelement
                };
            }

            // Call the "OnSerialized" method if any:
            CallOnSerializedMethod(obj, objectType);

            return(childrenNodes);
        }
        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);
            }
        }