Merge pull request #347 from JamesB7/master
[mono.git] / mcs / class / System.Runtime.Serialization / System.Runtime.Serialization / DataContractSerializer.cs
index 3cfe9d5515601b5e279495e0b6131b877f85f1c2..45fd1f7091315903859c8d9ca9f7bccc80d15eee 100755 (executable)
 // distribute, sublicense, and/or sell copies of the Software, and to
 // permit persons to whom the Software is furnished to do so, subject to
 // the following conditions:
-// 
+//
 // The above copyright notice and this permission notice shall be
 // included in all copies or substantial portions of the Software.
-// 
+//
 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
@@ -51,6 +51,7 @@ namespace System.Runtime.Serialization
                StreamingContext context;
                ReadOnlyCollection<Type> returned_known_types;
                KnownTypeCollection known_types;
+               List<Type> specified_known_types;
                IDataContractSurrogate surrogate;
                DataContractResolver resolver, default_resolver;
 
@@ -76,7 +77,7 @@ namespace System.Runtime.Serialization
                        QName qname = known_types.GetQName (type);
 
                        FillDictionaryString (qname.Name, qname.Namespace);
-                       
+
                }
 
                public DataContractSerializer (Type type, string rootName,
@@ -216,22 +217,38 @@ namespace System.Runtime.Serialization
                void PopulateTypes (IEnumerable<Type> knownTypes)
                {
                        if (known_types == null)
-                               known_types= new KnownTypeCollection ();
+                               known_types = new KnownTypeCollection ();
+
+                       if (specified_known_types == null)
+                               specified_known_types = new List<Type> ();
 
                        if (knownTypes != null) {
-                               foreach (Type t in knownTypes)
+                               foreach (Type t in knownTypes) {
                                        known_types.Add (t);
+                                       specified_known_types.Add (t);
+                               }
                        }
 
+                       RegisterTypeAsKnown (type);
+               }
+
+               void RegisterTypeAsKnown (Type type)
+               {
+                       if (known_types.Contains (type))
+                               return;
+
                        Type elementType = type;
                        if (type.HasElementType)
                                elementType = type.GetElementType ();
 
+                       known_types.Add (elementType);
+
                        /* Get all KnownTypeAttribute-s, including inherited ones */
                        object [] attrs = elementType.GetCustomAttributes (typeof (KnownTypeAttribute), true);
                        for (int i = 0; i < attrs.Length; i ++) {
                                KnownTypeAttribute kt = (KnownTypeAttribute) attrs [i];
-                               known_types.Add (kt.Type);
+                               foreach (var t in kt.GetTypes (elementType))
+                                       RegisterTypeAsKnown (t);
                        }
                }
 
@@ -277,7 +294,7 @@ namespace System.Runtime.Serialization
                public ReadOnlyCollection<Type> KnownTypes {
                        get {
                                if (returned_known_types == null)
-                                       returned_known_types = new ReadOnlyCollection<Type> (known_types);
+                                       returned_known_types = new ReadOnlyCollection<Type> (specified_known_types);
                                return returned_known_types;
                        }
                }
@@ -354,18 +371,6 @@ namespace System.Runtime.Serialization
                }
 #endif
 
-               private void ReadRootStartElement (XmlReader reader, Type type)
-               {
-                       SerializationMap map =
-                               known_types.FindUserMap (type);
-                       QName name = map != null ? map.XmlName :
-                               KnownTypeCollection.GetPredefinedTypeName (type);
-                       reader.MoveToContent ();
-                       reader.ReadStartElement (name.Name, name.Namespace);
-                       // FIXME: could there be any attributes to handle here?
-                       reader.Read ();
-               }
-
                // SP1
                public override void WriteObject (XmlWriter writer, object graph)
                {
@@ -433,7 +438,7 @@ namespace System.Runtime.Serialization
                        XmlDictionaryWriter writer, object graph)
                {
                        Type rootType = type;
-                       
+
                        if (root_name.Value == "")
                                throw new InvalidDataContractException ("Type '" + type.ToString () +
                                        "' cannot have a DataContract attribute Name set to null or empty string.");
@@ -457,8 +462,7 @@ namespace System.Runtime.Serialization
 
                        if (rootQName == null &&
                            graph.GetType () != type &&
-                           !known_types.Contains (graph.GetType ()) &&
-                           KnownTypeCollection.GetPrimitiveTypeName (graph.GetType ()) == QName.Empty)
+                           IsUnknownType (graph.GetType ()))
                                throw new SerializationException (String.Format ("Type '{0}' is unexpected. The type should either be registered as a known type, or DataContractResolver should be used.", graph.GetType ()));
 
                        QName instName = rootQName;
@@ -486,7 +490,7 @@ namespace System.Runtime.Serialization
 
                        /* Different names */
                        known_types.Add (rootType);
-                       
+
                        instName = instName ?? KnownTypeCollection.GetPredefinedTypeName (graph.GetType ());
                        if (instName == QName.Empty)
                                /* Not a primitive type */
@@ -503,6 +507,16 @@ namespace System.Runtime.Serialization
 */
                }
 
+               bool IsUnknownType (Type type)
+               {
+                       if (known_types.Contains (type) ||
+                           KnownTypeCollection.GetPrimitiveTypeName (type) != QName.Empty)
+                               return false;
+                       if (type.IsArray)
+                               return IsUnknownType (type.GetElementType ());
+                       return true;
+               }
+
                public override void WriteEndObject (XmlDictionaryWriter writer)
                {
                        writer.WriteEndElement ();