예제 #1
0
        /// <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);
            }
        }
예제 #2
0
        // 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);
            }
        }
예제 #3
0
        /// <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;
                }
            }
        }
예제 #4
0
 // 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)
 {
 }
예제 #5
0
        /// <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);
        }