System.Xml.Serialization.XmlSerializationReader.ReadArray C# (CSharp) Method

ReadArray() private method

private ReadArray ( string typeName, string typeNs ) : object
typeName string
typeNs string
return object
        private object ReadArray(string typeName, string typeNs)
        {
            SoapArrayInfo arrayInfo;
            Type fallbackElementType = null;
            if (_soap12)
            {
                string itemType = _r.GetAttribute(_itemTypeID, _soap12NsID);
                string arraySize = _r.GetAttribute(_arraySizeID, _soap12NsID);
                Type arrayType = (Type)_types[new XmlQualifiedName(typeName, typeNs)];
                // no indication that this is an array?
                if (itemType == null && arraySize == null && (arrayType == null || !arrayType.IsArray))
                    return null;

                arrayInfo = ParseSoap12ArrayType(itemType, arraySize);
                if (arrayType != null)
                    fallbackElementType = TypeScope.GetArrayElementType(arrayType, null);
            }
            else
            {
                string arrayType = _r.GetAttribute(_arrayTypeID, _soapNsID);
                if (arrayType == null)
                    return null;

                arrayInfo = ParseArrayType(arrayType);
            }

            if (arrayInfo.dimensions != 1) throw new InvalidOperationException(SR.Format(SR.XmlInvalidArrayDimentions, CurrentTag()));

            // NOTE: don't use the array size that is specified since an evil client might pass
            // a number larger than the actual number of items in an attempt to harm the server.

            XmlQualifiedName qname;
            bool isPrimitive;
            Type elementType = null;
            XmlQualifiedName urTypeName = new XmlQualifiedName(_urTypeID, _schemaNsID);
            if (arrayInfo.qname.Length > 0)
            {
                qname = ToXmlQualifiedName(arrayInfo.qname, false);
                elementType = (Type)_types[qname];
            }
            else
                qname = urTypeName;

            // try again if the best we could come up with was object
            if (_soap12 && elementType == typeof(object))
                elementType = null;

            if (elementType == null)
            {
                if (!_soap12)
                {
                    elementType = GetPrimitiveType(qname, true);
                    isPrimitive = true;
                }
                else
                {
                    // try it as a primitive
                    if (qname != urTypeName)
                        elementType = GetPrimitiveType(qname, false);
                    if (elementType != null)
                    {
                        isPrimitive = true;
                    }
                    else
                    {
                        // still nothing: go with fallback type or object
                        if (fallbackElementType == null)
                        {
                            elementType = typeof(object);
                            isPrimitive = false;
                        }
                        else
                        {
                            elementType = fallbackElementType;
                            XmlQualifiedName newQname = (XmlQualifiedName)_typesReverse[elementType];
                            if (newQname == null)
                            {
                                newQname = XmlSerializationWriter.GetPrimitiveTypeNameInternal(elementType);
                                isPrimitive = true;
                            }
                            else
                                isPrimitive = elementType.GetTypeInfo().IsPrimitive;
                            if (newQname != null) qname = newQname;
                        }
                    }
                }
            }
            else
                isPrimitive = elementType.GetTypeInfo().IsPrimitive;

            if (!_soap12 && arrayInfo.jaggedDimensions > 0)
            {
                for (int i = 0; i < arrayInfo.jaggedDimensions; i++)
                    elementType = elementType.MakeArrayType();
            }

            if (_r.IsEmptyElement)
            {
                _r.Skip();
                return Array.CreateInstance(elementType, 0);
            }

            _r.ReadStartElement();
            _r.MoveToContent();

            int arrayLength = 0;
            Array array = null;

            if (elementType.GetTypeInfo().IsValueType)
            {
                if (!isPrimitive && !elementType.GetTypeInfo().IsEnum)
                {
                    throw new NotSupportedException(SR.Format(SR.XmlRpcArrayOfValueTypes, elementType.FullName));
                }
                // CONSIDER, erikc, we could have specialized read functions here
                // for primitives, which would avoid boxing.
                int whileIterations = 0;
                int readerCount = ReaderCount;
                while (_r.NodeType != XmlNodeType.EndElement)
                {
                    array = EnsureArrayIndex(array, arrayLength, elementType);
                    array.SetValue(ReadReferencedElement(qname.Name, qname.Namespace), arrayLength);
                    arrayLength++;
                    _r.MoveToContent();
                    CheckReaderCount(ref whileIterations, ref readerCount);
                }
                array = ShrinkArray(array, arrayLength, elementType, false);
            }
            else
            {
                string type;
                string typens;
                string[] ids = null;
                int idsLength = 0;

                int whileIterations = 0;
                int readerCount = ReaderCount;
                while (_r.NodeType != XmlNodeType.EndElement)
                {
                    array = EnsureArrayIndex(array, arrayLength, elementType);
                    ids = (string[])EnsureArrayIndex(ids, idsLength, typeof(string));
                    // CONSIDER: i'm not sure it's correct to let item name take precedence over arrayType
                    if (_r.NamespaceURI.Length != 0)
                    {
                        type = _r.LocalName;
                        if ((object)_r.NamespaceURI == (object)_soapNsID)
                            typens = XmlSchema.Namespace;
                        else
                            typens = _r.NamespaceURI;
                    }
                    else
                    {
                        type = qname.Name;
                        typens = qname.Namespace;
                    }
                    array.SetValue(ReadReferencingElement(type, typens, out ids[idsLength]), arrayLength);
                    arrayLength++;
                    idsLength++;
                    // CONSIDER, erikc, sparse arrays, perhaps?
                    _r.MoveToContent();
                    CheckReaderCount(ref whileIterations, ref readerCount);
                }

                // special case for soap 1.2: try to get a better fit than object[] when no metadata is known
                // this applies in the doc/enc/bare case
                if (_soap12 && elementType == typeof(object))
                {
                    Type itemType = null;
                    for (int i = 0; i < arrayLength; i++)
                    {
                        object currItem = array.GetValue(i);
                        if (currItem != null)
                        {
                            Type currItemType = currItem.GetType();
                            if (currItemType.GetTypeInfo().IsValueType)
                            {
                                itemType = null;
                                break;
                            }
                            if (itemType == null || currItemType.IsAssignableFrom(itemType))
                            {
                                itemType = currItemType;
                            }
                            else if (!itemType.IsAssignableFrom(currItemType))
                            {
                                itemType = null;
                                break;
                            }
                        }
                    }
                    if (itemType != null)
                        elementType = itemType;
                }
                ids = (string[])ShrinkArray(ids, idsLength, typeof(string), false);
                array = ShrinkArray(array, arrayLength, elementType, false);
                Fixup fixupArray = new Fixup(array, new XmlSerializationFixupCallback(this.FixupArrayRefs), ids);
                AddFixup(fixupArray);
            }

            // CONSIDER, erikc, check to see if the specified array length was right, perhaps?

            ReadEndElement();
            return array;
        }