/// <remarks> /// This constructor is used to create internal sub serializers. /// </remarks> /// <inheritdoc /> private XmlSerializer(Type targetType, SubSerializerCollection subSerializers, XmlSerializationSettings settings) { if (targetType == null) { throw new ArgumentNullException(); } if (subSerializers == null) { throw new ArgumentNullException(); } this.targetType = targetType; // Reflect basic type data and check if its possible to serialize/deserialize this type at all. try { this.ValidateAndGetRootAttribute(settings, null, out this.rootAttribute); } catch (XmlSerializationException exception) { throw new ArgumentException( String.Format( CultureInfo.CurrentCulture, "The target type is invalid because: {0}. See inner exception for more details.", exception.Message ), "targetType", exception); } this.isSubSerializer = true; this.subSerializers = subSerializers; this.settings = settings; // Enumerate reflection data of each member. try { this.ReflectTypeData(); } catch (XmlSerializationException exception) { throw new ArgumentException( String.Format( CultureInfo.CurrentCulture, "The target type is not serializable because: {0}. See inner exception for more details.", exception.Message ), "targetType", exception); } }
// This constructor is used by the derived non-generic serializer. /// <exception cref="ArgumentException"> /// The given type is not serializable or the <see cref="XmlSerializationSettings" /> are invalid. /// </exception> protected XmlSerializer( Type targetType, XmlSerializationSettings settings = default(XmlSerializationSettings), XmlRootAttribute rootAttributeOverride = null, IEnumerable <Type> typesToCache = null, Boolean isGeneric = true ) { if (targetType == null) { throw new ArgumentNullException(); } this.targetType = targetType; this.settings = settings; if (this.settings.Equals(default(XmlSerializationSettings))) { this.settings = XmlSerializationSettings.Default; } try { this.Settings.Validate(); } catch (ValidationException exception) { throw new ArgumentException( String.Format( CultureInfo.CurrentCulture, "The settings are not valid because: {0}. See inner exception for more details.", exception.Message ), "settings", exception); } if (this.Settings.NullAttributeName == null) { this.settings.NullAttributeName = XmlSerializer.DefaultNullAttributeName; } if (this.Settings.CultureInfo == null) { this.settings.CultureInfo = CultureInfo.CurrentCulture; } // Reflect basic type data and check if its possible to serialize/deserialize this type at all. try { this.ValidateAndGetRootAttribute(this.settings, rootAttributeOverride, out this.rootAttribute); } catch (XmlSerializationException exception) { String paramName = isGeneric ? "T" : "targetType"; throw new ArgumentException( String.Format( CultureInfo.CurrentCulture, "The target type is invalid because: {0}. See inner exception for more details.", exception.Message ), paramName, exception); } this.subSerializers = new SubSerializerCollection(10); // Enumerate reflection data of each member. try { this.ReflectTypeData(typesToCache); } catch (XmlSerializationException exception) { String paramName = isGeneric ? "T" : "targetType"; throw new ArgumentException( String.Format( CultureInfo.CurrentCulture, "The target type is invalid because: {0}. See inner exception for more details.", exception.Message ), paramName, exception); } }
/// <exception cref="ArgumentException"> /// <see cref="T" /> is no class or struct or is an abstract class. /// </exception> private void ValidateAndGetRootAttribute( XmlSerializationSettings settings, XmlRootAttribute rootAttributeOverride, out XmlRootAttribute rootAttribute ) { Contract.Ensures(Contract.ValueAtReturn <XmlRootAttribute>(out rootAttribute) != null); if (!this.TargetType.IsClass && !this.TargetType.IsValueType) { throw new XmlSerializationException("Type argument T has to be either a class or struct type."); } if (this.TargetType.IsAbstract) { throw new XmlSerializationException("Type argument T can not be an abstract class."); } if (this.TargetType.IsSubclassOf(typeof(Enum))) { throw new XmlSerializationException("Type argument T can not be an enumeration."); } if (rootAttributeOverride != null) { rootAttribute = rootAttributeOverride; } else { // Reflect the root attribute. rootAttribute = null; foreach (Object attribute in this.TargetType.GetCustomAttributes(false)) { XmlRootAttribute foundAttribute = (attribute as XmlRootAttribute); if (foundAttribute != null) { rootAttribute = foundAttribute; break; } } } if (rootAttribute == null) { if (!settings.RequiresExplicitXmlMetadataAttributes) { rootAttribute = new XmlRootAttribute(); } else { var ex = new XmlSerializationException("The type is not serializable because it does not define an XmlRootAttribute."); ex.Data.Add("Type Name", this.TargetType.FullName); throw ex; } } // Get a name for the root attribute if necessary. if (this.rootAttribute.Name == null) { if (!XmlReader.IsName(this.TargetType.Name)) { var ex = new XmlSerializationException( "The XmlRootAttribute does not define a custom name and the name of the class is not a valid name for an xml element."); ex.Data.Add("Class Name", this.TargetType.Name); throw ex; } this.rootAttribute.Name = this.TargetType.Name; } else { if (!XmlReader.IsName(this.rootAttribute.Name)) { var ex = new XmlSerializationException("The XmlRootAttribute does not define a valid name for an xml element."); ex.Data.Add("Root Name", this.rootAttribute.Name); throw ex; } } }
// This constructor is used for the root serializer created by the user. /// <exception cref="ArgumentException"> /// The given type is not serializable or the <see cref="XmlSerializationSettings" /> are invalid. /// </exception> public XmlSerializer( XmlSerializationSettings settings = default(XmlSerializationSettings), XmlRootAttribute rootAttributeOverride = null, IEnumerable <Type> typesToCache = null ) : this(typeof(T), settings, rootAttributeOverride, typesToCache) { }
/// <exception cref="ArgumentException"> /// The reflected data are invalid. /// </exception> public static XmlSerializableMember Create( MemberInfo memberInfo, ICollection <Type> typesToCache, XmlSerializationSettings settings ) { if (memberInfo == null) { throw new ArgumentNullException(); } if (typesToCache == null) { throw new ArgumentNullException(); } FieldInfo fieldInfo = (memberInfo as FieldInfo); PropertyInfo propertyInfo = (memberInfo as PropertyInfo); if (fieldInfo == null && propertyInfo == null) { return(null); } XmlSerializableMember serializableMember = new XmlSerializableMember(fieldInfo, propertyInfo); Type memberType; if (fieldInfo != null) { memberType = fieldInfo.FieldType; } else { memberType = propertyInfo.PropertyType; } // This check includes IList, ICollection, IEnumerable<T>, IList<T>, ICollection<T>. Type collectionItemType = null; Boolean isCollection = (memberType != typeof(String) && typeof(IEnumerable).IsAssignableFrom(memberType)); Boolean isDictionary = (typeof(IDictionary).IsAssignableFrom(memberType) || typeof(IDictionary <,>).IsAssignableFrom(memberType)); if (isCollection) { if (memberType.IsGenericType) { if (!isDictionary) { collectionItemType = memberType.GetGenericArguments()[0]; } else { Type[] genericArgumentTypes = memberType.GetGenericArguments(); // TODO: There may be a better approach for this. collectionItemType = Type.GetType(String.Format( "System.Collections.Generic.KeyValuePair`2[[{0}],[{1}]]", genericArgumentTypes[0].AssemblyQualifiedName, genericArgumentTypes[1].AssemblyQualifiedName )); } } else { if (!isDictionary) { collectionItemType = typeof(Object); } else { collectionItemType = typeof(KeyValuePair <Object, Object>); } } } Boolean isSerializable = false; String memberName = null; Int32 orderIndex = 0; String comment = null; Boolean isAttribute = false; XmlItemDefAttributeCollection itemDefAttributes = new XmlItemDefAttributeCollection(); XmlTypeDefAttributeCollection typeDefAttributes = new XmlTypeDefAttributeCollection(); if (!settings.RequiresExplicitXmlMetadataAttributes) { // With this settings, any field or property is serializable by default. memberName = memberInfo.Name; isSerializable = true; } foreach (Attribute attribute in memberInfo.GetCustomAttributes(true)) { if (attribute is XmlNodeAttribute) { XmlNodeAttribute nodeAttribute = (XmlNodeAttribute)attribute; if (nodeAttribute.Name == null) { memberName = memberInfo.Name; } else { memberName = nodeAttribute.Name; } if (nodeAttribute.OrderIndex == -1 && settings.RequiresExplicitOrder) { var ex = new ArgumentException("The XmlNodeAttribute on the member does not define an explicit order index as required by the current serialization settings."); ex.Data.Add("Member Info", memberInfo); throw ex; } comment = nodeAttribute.Comment; orderIndex = nodeAttribute.OrderIndex; isAttribute = nodeAttribute.IsAttribute; isSerializable = true; continue; } if (attribute is XmlNodeTypeDefAttribute) { XmlNodeTypeDefAttribute typeDefAttribute = (XmlNodeTypeDefAttribute)attribute; if (memberType == typeDefAttribute.Type) { var ex = new ArgumentException("XmlNodeTypeDefAttribute can not be of the same type as the member."); ex.Data.Add("Member Info", memberInfo); throw ex; } if (!memberType.IsAssignableFrom(typeDefAttribute.Type)) { var ex = new ArgumentException("XmlNodeTypeDefAttribute defined with a type which is not castable to the member's type."); ex.Data.Add("Member Info", memberInfo); throw ex; } typeDefAttributes.Add(typeDefAttribute); } if (attribute is XmlItemDefAttribute) { if (!isCollection) { var ex = new ArgumentException("XmlItemDefAttribute defined for a member of a type that does not implement the IEnumerable or IEnumerable<T> interface."); ex.Data.Add("Member Info", memberInfo); throw ex; } XmlItemDefAttribute itemDefAttribute = (XmlItemDefAttribute)attribute; // Check if the type defined by the XmlItemDefAttribute is derived or equal to the collection's item type. if (!collectionItemType.IsAssignableFrom(itemDefAttribute.Type)) { var ex = new ArgumentException("The type given by the XmlItemDefAttribute is not assignable to the item type of the collection."); ex.Data.Add("Member Info", memberInfo); throw ex; } // Check if we have an item attribute for this type already. if (itemDefAttributes.Contains(itemDefAttribute.Type)) { var ex = new ArgumentException("Only one XmlItemDefAttribute is allowed for the same item type."); ex.Data.Add("Item Type", itemDefAttribute.Type); ex.Data.Add("Member Info", memberInfo); throw ex; } itemDefAttributes.Add(itemDefAttribute); typesToCache.Add(itemDefAttribute.Type); } } if (!isSerializable) { return(null); } if (settings.RequiresExplicitCollectionItemDefinition && isCollection && !itemDefAttributes.ContainsType(collectionItemType)) { var ex = new ArgumentException("The collection member does not define an explicit XmlItemDefAttribute for its type as required by the current serialization settings."); ex.Data.Add("Member Info", memberInfo); ex.Data.Add("Item Type", collectionItemType); throw ex; } Boolean isStatic; if (fieldInfo != null) { isStatic = fieldInfo.IsStatic; } else { // We need at least one accessor to check whether the property is static etc. MethodInfo[] accessors = propertyInfo.GetAccessors(true); if (accessors.Length == 0) { var ex = new ArgumentException("A XML-Serializable property requires at least one accessor."); ex.Data.Add("Property Info", serializableMember.MemberInfo); throw ex; } MethodInfo accessor = accessors[0]; if (accessor.IsAbstract) { var ex = new ArgumentException("A XML-Serializable property can not be abstract."); ex.Data.Add("Property Info", serializableMember.MemberInfo); throw ex; } isStatic = accessor.IsStatic; } // If any field or property should be serializable, we may not include static members. if (isStatic && !settings.RequiresExplicitXmlMetadataAttributes) { return(null); } serializableMember.memberInfo = new XmlMemberInfo( memberName, memberType, orderIndex, comment, isAttribute, isStatic, isCollection, collectionItemType, itemDefAttributes, typeDefAttributes ); if (collectionItemType != null) { typesToCache.Add(collectionItemType); } typesToCache.Add(memberType); return(serializableMember); }