Merge pull request #1275 from ranma42/fix-lib64
[mono.git] / mcs / class / System.XML / System.Xml.Serialization / TypeData.cs
index 5c8c480f3f03b7e924d41beb411ee9e1bf196458..861fcc11de67455023df3b2fbe422a78319b02ec 100644 (file)
@@ -42,6 +42,30 @@ using System.Xml.Schema;
 
 namespace System.Xml.Serialization
 {
+       [AttributeUsage (AttributeTargets.Class, AllowMultiple = false)]
+       internal class XmlTypeConvertorAttribute : Attribute
+       {
+               /*
+                * Bug #12571:
+                * 
+                * System.Xml.Linq.XElement should be deserializable from an XmlElement.
+                * 
+                * Types can now register a custom deserializer by adding this custom attribute.
+                * Method is the name of a private 'static method (static object)' method that will
+                * be invoked to construct an instance of the object.
+                * 
+                */
+               public string Method {
+                       get;
+                       private set;
+               }
+
+               public XmlTypeConvertorAttribute (string method)
+               {
+                       Method = method;
+               }
+       }
+
        internal class TypeData
        {
                Type type;
@@ -56,6 +80,7 @@ namespace System.Xml.Serialization
                TypeData listTypeData;
                TypeData mappedType;
                XmlSchemaPatternFacet facet;
+               MethodInfo typeConvertor;
                bool hasPublicConstructor = true;
                bool nullableOverride;
 
@@ -98,6 +123,8 @@ namespace System.Xml.Serialization
                        if (sType == SchemaTypes.Array || sType == SchemaTypes.Class) {
                                hasPublicConstructor = !type.IsInterface && (type.IsArray || type.GetConstructor (Type.EmptyTypes) != null || type.IsAbstract || type.IsValueType);
                        }
+
+                       LookupTypeConvertor ();
                }
 
                internal TypeData (string typeName, string fullTypeName, string xmlType, SchemaTypes schemaType, TypeData listItemTypeData)
@@ -110,6 +137,23 @@ namespace System.Xml.Serialization
                        this.hasPublicConstructor = true;
                }
 
+               void LookupTypeConvertor ()
+               {
+#if NET_4_5
+                       // We only need this for System.Xml.Linq.
+                       var convertor = type.GetCustomAttribute<XmlTypeConvertorAttribute> ();
+                       if (convertor != null)
+                               typeConvertor = type.GetMethod (convertor.Method, BindingFlags.Static | BindingFlags.NonPublic);
+#endif
+               }
+
+               internal void ConvertForAssignment (ref object value)
+               {
+                       // Has this object registered a custom type converter?
+                       if (typeConvertor != null)
+                               value = typeConvertor.Invoke (null, new object[] { value });
+               }
+
                public string TypeName
                {
                        get {
@@ -442,10 +486,13 @@ namespace System.Xml.Serialization
                };
 
 #if NET_2_0
-               private Type GetGenericListItemType (Type type)
+               internal static Type GetGenericListItemType (Type type)
                {
-                       if (type.IsGenericType && type.GetGenericTypeDefinition () == typeof (ICollection<>))
-                               return type.GetGenericArguments () [0];
+                       if (type.IsGenericType && typeof(IEnumerable).IsAssignableFrom(type.GetGenericTypeDefinition ())) {
+                               Type [] gatypes = type.GetGenericArguments ();
+                               if (type.GetMethod ("Add", gatypes) != null)
+                                       return gatypes [0];
+                       }
                        Type t = null;
                        foreach (Type i in type.GetInterfaces ())
                                if ((t = GetGenericListItemType (i)) != null)