+#if !NET_4_5
+ public static T GetCustomAttribute<T> (this MemberInfo type, bool inherit)
+ {
+ var arr = type.GetCustomAttributes (typeof (T), inherit);
+ return arr != null && arr.Length == 1 ? (T) arr [0] : default (T);
+ }
+#endif
+ public static IEnumerable<Type> GetInterfacesOrSelfInterface (this Type type)
+ {
+ if (type.IsInterface)
+ yield return type;
+ foreach (var t in type.GetInterfaces ())
+ yield return t;
+ }
+
+ public static bool ImplementsInterface (this Type type, Type iface)
+ {
+ foreach (var t in type.GetInterfacesOrSelfInterface ()) {
+ if (t == iface)
+ return true;
+ }
+
+ var baseType = type.BaseType;
+ if (baseType != null)
+ return baseType.ImplementsInterface (iface);
+
+ return false;
+ }
+ }
+
+ internal sealed class KnownTypeCollection : Collection<Type>
+ {
+ internal const string MSSimpleNamespace =
+ "http://schemas.microsoft.com/2003/10/Serialization/";
+ internal const string MSArraysNamespace =
+ "http://schemas.microsoft.com/2003/10/Serialization/Arrays";
+ internal const string DefaultClrNamespaceBase =
+ "http://schemas.datacontract.org/2004/07/";
+ internal const string DefaultClrNamespaceSystem =
+ "http://schemas.datacontract.org/2004/07/System";
+
+
+ static QName any_type, bool_type,
+ byte_type, date_type, decimal_type, double_type,
+ float_type, string_type,
+ short_type, int_type, long_type,
+ ubyte_type, ushort_type, uint_type, ulong_type,
+ // non-TypeCode
+ any_uri_type, base64_type, duration_type, qname_type,
+ // custom in ms nsURI schema
+ char_type, guid_type,
+ // not in ms nsURI schema
+ dbnull_type, date_time_offset_type;
+
+ // XmlSchemaType.GetBuiltInPrimitiveType() does not exist in moonlight, so I had to explicitly add them. And now that we have it, it does not make much sense to use #if MOONLIGHT ... #endif for XmlSchemaType anymore :-(
+ static Dictionary<string,Type> xs_predefined_types = new Dictionary<string,Type> ();
+
+ static KnownTypeCollection ()
+ {
+ string s = MSSimpleNamespace;
+ any_type = new QName ("anyType", s);
+ any_uri_type = new QName ("anyURI", s);
+ bool_type = new QName ("boolean", s);
+ base64_type = new QName ("base64Binary", s);
+ date_type = new QName ("dateTime", s);
+ duration_type = new QName ("duration", s);
+ qname_type = new QName ("QName", s);
+ decimal_type = new QName ("decimal", s);
+ double_type = new QName ("double", s);
+ float_type = new QName ("float", s);
+ byte_type = new QName ("byte", s);
+ short_type = new QName ("short", s);
+ int_type = new QName ("int", s);
+ long_type = new QName ("long", s);
+ ubyte_type = new QName ("unsignedByte", s);
+ ushort_type = new QName ("unsignedShort", s);
+ uint_type = new QName ("unsignedInt", s);
+ ulong_type = new QName ("unsignedLong", s);
+ string_type = new QName ("string", s);
+ guid_type = new QName ("guid", s);
+ char_type = new QName ("char", s);
+
+ dbnull_type = new QName ("DBNull", DefaultClrNamespaceBase + "System");
+ date_time_offset_type = new QName ("DateTimeOffset", DefaultClrNamespaceBase + "System");
+
+ xs_predefined_types.Add ("string", typeof (string));
+ xs_predefined_types.Add ("boolean", typeof (bool));
+ xs_predefined_types.Add ("float", typeof (float));
+ xs_predefined_types.Add ("double", typeof (double));
+ xs_predefined_types.Add ("decimal", typeof (decimal));
+ xs_predefined_types.Add ("duration", typeof (TimeSpan));
+ xs_predefined_types.Add ("dateTime", typeof (DateTime));
+ xs_predefined_types.Add ("date", typeof (DateTime));
+ xs_predefined_types.Add ("time", typeof (DateTime));
+ xs_predefined_types.Add ("gYearMonth", typeof (DateTime));
+ xs_predefined_types.Add ("gYear", typeof (DateTime));
+ xs_predefined_types.Add ("gMonthDay", typeof (DateTime));
+ xs_predefined_types.Add ("gDay", typeof (DateTime));
+ xs_predefined_types.Add ("gMonth", typeof (DateTime));
+ xs_predefined_types.Add ("hexBinary", typeof (byte []));
+ xs_predefined_types.Add ("base64Binary", typeof (byte []));
+ xs_predefined_types.Add ("anyURI", typeof (Uri));
+ xs_predefined_types.Add ("QName", typeof (QName));
+ xs_predefined_types.Add ("NOTATION", typeof (string));
+
+ xs_predefined_types.Add ("normalizedString", typeof (string));
+ xs_predefined_types.Add ("token", typeof (string));
+ xs_predefined_types.Add ("language", typeof (string));
+ xs_predefined_types.Add ("IDREFS", typeof (string []));
+ xs_predefined_types.Add ("ENTITIES", typeof (string []));
+ xs_predefined_types.Add ("NMTOKEN", typeof (string));
+ xs_predefined_types.Add ("NMTOKENS", typeof (string []));
+ xs_predefined_types.Add ("Name", typeof (string));
+ xs_predefined_types.Add ("NCName", typeof (string));
+ xs_predefined_types.Add ("ID", typeof (string));
+ xs_predefined_types.Add ("IDREF", typeof (string));
+ xs_predefined_types.Add ("ENTITY", typeof (string));
+
+ xs_predefined_types.Add ("integer", typeof (decimal));
+ xs_predefined_types.Add ("nonPositiveInteger", typeof (int));
+ xs_predefined_types.Add ("negativeInteger", typeof (int));
+ xs_predefined_types.Add ("long", typeof (long));
+ xs_predefined_types.Add ("int", typeof (int));
+ xs_predefined_types.Add ("short", typeof (short));
+ xs_predefined_types.Add ("byte", typeof (sbyte));
+ xs_predefined_types.Add ("nonNegativeInteger", typeof (decimal));
+ xs_predefined_types.Add ("unsignedLong", typeof (ulong));
+ xs_predefined_types.Add ("unsignedInt", typeof (uint));
+ xs_predefined_types.Add ("unsignedShort", typeof (ushort));
+ xs_predefined_types.Add ("unsignedByte", typeof (byte));
+ xs_predefined_types.Add ("positiveInteger", typeof (decimal));
+
+ xs_predefined_types.Add ("anyType", typeof (object));
+ }
+
+ // FIXME: find out how QName and guid are processed
+
+ internal QName GetXmlName (Type type)
+ {
+ SerializationMap map = FindUserMap (type);
+ if (map != null)
+ return map.XmlName;
+ return GetPredefinedTypeName (type);
+ }
+
+ internal static QName GetPredefinedTypeName (Type type)
+ {
+ QName name = GetPrimitiveTypeName (type);
+ if (name != QName.Empty)
+ return name;
+ if (type == typeof (DBNull))
+ return dbnull_type;
+ return QName.Empty;
+ }
+
+ internal static QName GetPrimitiveTypeName (Type type)
+ {
+ if (type.IsGenericType && type.GetGenericTypeDefinition () == typeof (Nullable<>))
+ return GetPrimitiveTypeName (type.GetGenericArguments () [0]);
+
+ if (type.IsEnum)
+ return QName.Empty;
+
+ switch (Type.GetTypeCode (type)) {
+ case TypeCode.Object: // other than System.Object
+ case TypeCode.DBNull: // it is natively mapped, but not in ms serialization namespace.
+ case TypeCode.Empty:
+ default:
+ if (type == typeof (object))
+ return any_type;
+ if (type == typeof (Guid))
+ return guid_type;
+ if (type == typeof (TimeSpan))
+ return duration_type;
+ if (type == typeof (byte []))
+ return base64_type;
+ if (type == typeof (Uri))
+ return any_uri_type;
+ if (type == typeof (DateTimeOffset))
+ return date_time_offset_type;
+ return QName.Empty;
+ case TypeCode.Boolean:
+ return bool_type;
+ case TypeCode.Byte:
+ return ubyte_type;
+ case TypeCode.Char:
+ return char_type;
+ case TypeCode.DateTime:
+ return date_type;
+ case TypeCode.Decimal:
+ return decimal_type;
+ case TypeCode.Double:
+ return double_type;
+ case TypeCode.Int16:
+ return short_type;
+ case TypeCode.Int32:
+ return int_type;
+ case TypeCode.Int64:
+ return long_type;
+ case TypeCode.SByte:
+ return byte_type;
+ case TypeCode.Single:
+ return float_type;
+ case TypeCode.String:
+ return string_type;
+ case TypeCode.UInt16:
+ return ushort_type;
+ case TypeCode.UInt32:
+ return uint_type;
+ case TypeCode.UInt64:
+ return ulong_type;
+ }
+ }
+
+ internal static string PredefinedTypeObjectToString (object obj)
+ {
+ Type type = obj.GetType ();
+ switch (Type.GetTypeCode (type)) {
+ case TypeCode.Object: // other than System.Object
+ case TypeCode.Empty:
+ default:
+ if (type == typeof (object))
+ return String.Empty;
+ if (type == typeof (Guid))
+ return XmlConvert.ToString ((Guid) obj);
+ if (type == typeof (TimeSpan))
+ return XmlConvert.ToString ((TimeSpan) obj);
+ if (type == typeof (byte []))
+ return Convert.ToBase64String ((byte []) obj);
+ if (type == typeof (Uri))
+ return ((Uri) obj).ToString ();
+ throw new Exception ("Internal error: missing predefined type serialization for type " + type.FullName);
+ case TypeCode.DBNull: // predefined, but not primitive
+ return String.Empty;
+ case TypeCode.Boolean:
+ return XmlConvert.ToString ((bool) obj);
+ case TypeCode.Byte:
+ return XmlConvert.ToString ((int)((byte) obj));
+ case TypeCode.Char:
+ return XmlConvert.ToString ((uint) (char) obj);
+ case TypeCode.DateTime:
+ return XmlConvert.ToString ((DateTime) obj, XmlDateTimeSerializationMode.RoundtripKind);
+ case TypeCode.Decimal:
+ return XmlConvert.ToString ((decimal) obj);
+ case TypeCode.Double:
+ return XmlConvert.ToString ((double) obj);
+ case TypeCode.Int16:
+ return XmlConvert.ToString ((short) obj);
+ case TypeCode.Int32:
+ return XmlConvert.ToString ((int) obj);
+ case TypeCode.Int64:
+ return XmlConvert.ToString ((long) obj);
+ case TypeCode.SByte:
+ return XmlConvert.ToString ((sbyte) obj);
+ case TypeCode.Single:
+ return XmlConvert.ToString ((float) obj);
+ case TypeCode.String:
+ return (string) obj;
+ case TypeCode.UInt16:
+ return XmlConvert.ToString ((int) (ushort) obj);
+ case TypeCode.UInt32:
+ return XmlConvert.ToString ((uint) obj);
+ case TypeCode.UInt64:
+ return XmlConvert.ToString ((ulong) obj);
+ }
+ }
+
+ internal static Type GetPrimitiveTypeFromName (QName name)
+ {
+ switch (name.Namespace) {
+ case DefaultClrNamespaceSystem:
+ switch (name.Name) {
+ case "DBNull":
+ return typeof (DBNull);
+ case "DateTimeOffset":
+ return typeof (DateTimeOffset);
+ }
+ break;
+ case XmlSchema.Namespace:
+ return xs_predefined_types.FirstOrDefault (p => p.Key == name.Name).Value;
+ case MSSimpleNamespace:
+ switch (name.Name) {
+ case "anyURI":
+ return typeof (Uri);
+ case "boolean":
+ return typeof (bool);
+ case "base64Binary":
+ return typeof (byte []);
+ case "dateTime":
+ return typeof (DateTime);
+ case "duration":
+ return typeof (TimeSpan);
+ case "QName":
+ return typeof (QName);
+ case "decimal":
+ return typeof (decimal);
+ case "double":
+ return typeof (double);
+ case "float":
+ return typeof (float);
+ case "byte":
+ return typeof (sbyte);
+ case "short":
+ return typeof (short);
+ case "int":
+ return typeof (int);
+ case "long":
+ return typeof (long);
+ case "unsignedByte":
+ return typeof (byte);
+ case "unsignedShort":
+ return typeof (ushort);
+ case "unsignedInt":
+ return typeof (uint);
+ case "unsignedLong":
+ return typeof (ulong);
+ case "string":
+ return typeof (string);
+ case "anyType":
+ return typeof (object);
+ case "guid":
+ return typeof (Guid);
+ case "char":
+ return typeof (char);
+ }
+ break;
+ }
+ return null;
+ }
+
+
+ internal static object PredefinedTypeStringToObject (string s,
+ string name, XmlReader reader)
+ {
+ switch (name) {
+ case "anyURI":
+ return new Uri(s,UriKind.RelativeOrAbsolute);
+ case "boolean":
+ return XmlConvert.ToBoolean (s);
+ case "base64Binary":
+ return Convert.FromBase64String (s);
+ case "dateTime":
+ return XmlConvert.ToDateTime (s, XmlDateTimeSerializationMode.RoundtripKind);
+ case "duration":
+ return XmlConvert.ToTimeSpan (s);
+ case "QName":
+ int idx = s.IndexOf (':');
+ string l = idx < 0 ? s : s.Substring (idx + 1);
+ return idx < 0 ? new QName (l) :
+ new QName (l, reader.LookupNamespace (
+ s.Substring (0, idx)));
+ case "decimal":
+ return XmlConvert.ToDecimal (s);
+ case "double":
+ return XmlConvert.ToDouble (s);
+ case "float":
+ return XmlConvert.ToSingle (s);
+ case "byte":
+ return XmlConvert.ToSByte (s);
+ case "short":
+ return XmlConvert.ToInt16 (s);
+ case "int":
+ return XmlConvert.ToInt32 (s);
+ case "long":
+ return XmlConvert.ToInt64 (s);
+ case "unsignedByte":
+ return XmlConvert.ToByte (s);
+ case "unsignedShort":
+ return XmlConvert.ToUInt16 (s);
+ case "unsignedInt":
+ return XmlConvert.ToUInt32 (s);
+ case "unsignedLong":
+ return XmlConvert.ToUInt64 (s);
+ case "string":
+ return s;
+ case "guid":
+ return XmlConvert.ToGuid (s);
+ case "anyType":
+ return s;
+ case "char":
+ return (char) XmlConvert.ToUInt32 (s);
+ default:
+ throw new Exception ("Unanticipated primitive type: " + name);
+ }
+ }
+
+ List<SerializationMap> contracts = new List<SerializationMap> ();
+