private Func <IXmlSerializerInternal> GetCreateSerializerFunc(PropertyInfo propertyInfo, IXmlSerializerOptions options)
        {
            var redactAttribute = (RedactAttribute)Attribute.GetCustomAttribute(propertyInfo, typeof(RedactAttribute));

            if (redactAttribute == null)
            {
                redactAttribute = options.RedactAttribute;
            }

            var attributeAttribute = (XmlAttributeAttribute)Attribute.GetCustomAttribute(propertyInfo, typeof(XmlAttributeAttribute));

            if (attributeAttribute != null)
            {
                var attributeName = !string.IsNullOrWhiteSpace(attributeAttribute.AttributeName) ? attributeAttribute.AttributeName : propertyInfo.Name;
                NodeType = NodeType.Attribute;
                Name     = attributeName;
                return(() => new XmlAttributeSerializer(propertyInfo.PropertyType, attributeName, redactAttribute, _encryptAttribute, options));
            }

            var textAttribute = (XmlTextAttribute)Attribute.GetCustomAttribute(propertyInfo, typeof(XmlTextAttribute));

            if (textAttribute != null)
            {
                NodeType = NodeType.Text;
                Name     = propertyInfo.Name;
                return(() => new XmlTextSerializer(propertyInfo.PropertyType, redactAttribute, _encryptAttribute, options.ExtraTypes));
            }

            if (redactAttribute != null)
            {
                options = options.WithRedactAttribute(redactAttribute);
            }

            var    elementAttribute = (XmlElementAttribute)Attribute.GetCustomAttribute(propertyInfo, typeof(XmlElementAttribute), false);
            string rootElementName;

            if (IsListProperty(propertyInfo))
            {
                var arrayAttribute     = (XmlArrayAttribute)Attribute.GetCustomAttribute(propertyInfo, typeof(XmlArrayAttribute), false);
                var arrayItemAttribute = (XmlArrayItemAttribute)Attribute.GetCustomAttribute(propertyInfo, typeof(XmlArrayItemAttribute), false);

                if (elementAttribute != null && (arrayAttribute != null || arrayItemAttribute != null))
                {
                    throw new InvalidOperationException("On list types, XmlElementAttribute may not be present with either XmlArrayAttribute or XmlArrayItemAttribute are present.");
                }

                string itemElementName;

                if (elementAttribute != null)
                {
                    rootElementName = null;
                    itemElementName = GetElementName(elementAttribute, x => x.ElementName, propertyInfo.Name);

                    Name = itemElementName;

                    _readsPastLastElement = () => true;
                }
                else
                {
                    rootElementName = GetElementName(arrayAttribute, x => x.ElementName, propertyInfo.Name);

                    var itemElementNameFallback =
                        propertyInfo.PropertyType.IsAssignableToGenericIEnumerable()
                            ? propertyInfo.PropertyType.GetGenericIEnumerableType().GetGenericArguments()[0].GetElementName()
                            : "Item";

                    itemElementName = GetElementName(arrayItemAttribute, x => x.ElementName, itemElementNameFallback);

                    Name = rootElementName;
                }

                NodeType = NodeType.Element;
                return(() => ListSerializer.GetSerializer(propertyInfo.PropertyType, _encryptAttribute, options.WithRootElementName(rootElementName), itemElementName));
            }

            rootElementName = GetElementName(elementAttribute, x => x.ElementName, propertyInfo.Name);

            NodeType = NodeType.Element;
            Name     = rootElementName;
            return(() => XmlSerializerFactory.Instance.GetSerializer(propertyInfo.PropertyType, _encryptAttribute, options.WithRootElementName(rootElementName)));
        }