예제 #1
0
        /// <summary>
        ///     Returns a collection with infos about all fields and properties of the type that can be (xml-)serialized
        /// </summary>
        /// <param name="type">Type to get information about</param>
        /// <returns></returns>
        public static IEnumerable <SFieldInfo> GetFieldInfos(this Type type)
        {
            List <SFieldInfo> result;

            if (_CacheFields.TryGetValue(type, out result))
            {
                return(result);
            }
            result = new List <SFieldInfo>();
            FieldInfo[] fields = type.GetFields(BindingFlags.Public | BindingFlags.Instance);
            foreach (FieldInfo field in fields)
            {
                if (field.HasAttribute <XmlIgnoreAttribute>() || field.Name.EndsWith("Specified"))
                {
                    continue;
                }
                SFieldInfo info = new SFieldInfo(field);
                _FillInfo(ref info, field);
                result.Add(info);
            }
            PropertyInfo[] properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
            foreach (PropertyInfo property in properties)
            {
                if (property.HasAttribute <XmlIgnoreAttribute>() || property.Name.EndsWith("Specified") || !property.CanRead || !property.CanWrite)
                {
                    continue;
                }
                SFieldInfo info = new SFieldInfo(property);
                _FillInfo(ref info, property);
                result.Add(info);
            }
            _CacheFields.Add(type, result);
            return(result);
        }
예제 #2
0
 /// <summary>
 ///     Sets the field to its default value if it has one (specified as DefaultValueAttribute or an empty collection if it is an embedded one)
 /// </summary>
 /// <param name="result"></param>
 /// <param name="field"></param>
 /// <returns>True if default value was set</returns>
 private static bool _CheckAndSetDefaultValue(object result, SFieldInfo field)
 {
     if (field.IsEmbeddedList)
     {
         _AddList(result, field, new List <object>());
         return(true);
     }
     if (!field.HasDefaultValue)
     {
         return(false);
     }
     field.SetValue(result, field.DefaultValue);
     return(true);
 }
예제 #3
0
        /// <summary>
        ///     Reads childnodes of the given node (either nodes or attributes)
        /// </summary>
        /// <param name="parent">Node to process</param>
        /// <param name="o">Object to put the values in</param>
        /// <param name="attributes">True for processing attributes, false for nodes</param>
        private void _ReadChildNodes(XmlNode parent, object o, bool attributes)
        {
            IEnumerable nodes;

            if (parent == null)
            {
                nodes = null;
            }
            else if (attributes)
            {
                nodes = parent.Attributes;
            }
            else
            {
                nodes = parent.ChildNodes;
            }

            List <SFieldInfo> fields = o.GetType().GetFields(attributes);

            if (nodes != null)
            {
                //Dictionary of all embedded lists to allow interleaved/mixed elements
                Dictionary <string, Tuple <SFieldInfo, List <object> > > embLists = new Dictionary <string, Tuple <SFieldInfo, List <object> > >();
                foreach (XmlNode node in nodes)
                {
                    if (node is XmlComment || node.LocalName == "xsd" || node.LocalName == "xsi")
                    {
                        continue;
                    }

                    SFieldInfo field = new SFieldInfo();
                    int        curField;
                    for (curField = 0; curField < fields.Count; curField++)
                    {
                        field = fields[curField];
                        if (field.Name == node.Name || field.AltName == node.Name || (field.IsEmbeddedList && node.Name.StartsWith(field.Name)))
                        {
                            break;
                        }
                    }
                    if (curField >= fields.Count)
                    {
                        string msg = "Unexpected element: %n";
                        if (fields.Count > 0)
                        {
                            msg += " Expected: " + string.Join(", ", fields.Select(f => f.Name));
                        }
                        _ErrorHandler.HandleError(new CXmlException(msg, node));
                        continue;
                    }

                    if (field.IsByteArray)
                    {
                        fields.RemoveAt(curField); //Do this also on error
                        byte[] value;
                        try
                        {
                            value = Convert.FromBase64String(node.InnerText);
                        }
                        catch (Exception)
                        {
                            _ErrorHandler.HandleError(new CXmlInvalidValueException("Invalid value in %n: %v", node, node.InnerText));
                            if (!_CheckAndSetDefaultValue(o, field))
                            {
                                _ErrorHandler.HandleError(new CXmlException("No default value for %n", node));
                            }
                            continue;
                        }
                        field.SetValue(o, value);
                    }
                    else if (field.IsEmbeddedList)
                    {
                        Tuple <SFieldInfo, List <object> > entry;
                        if (!embLists.TryGetValue(field.Name, out entry))
                        {
                            entry = new Tuple <SFieldInfo, List <object> >(field, new List <object>());
                            embLists.Add(field.Name, entry);
                        }
                        object subValue = _GetValue(node, field.SubType);
                        if (subValue != null)
                        {
                            entry.Item2.Add(subValue);
                        }
                    }
                    else
                    {
                        fields.RemoveAt(curField); //Do this also on error
                        object value = _GetValue(node, field.Type, field.ArrayItemName);
                        if (value == null)
                        {
                            if (_CheckAndSetDefaultValue(o, field))
                            {
                                continue;
                            }
                            if (!field.IsNullable)
                            {
                                _ErrorHandler.HandleError(new CXmlException("No default value for unset field at %n", node));
                                continue;
                            }
                        }
                        if (field.Ranged != null && value != null && !field.Ranged.IsValid(field.IsNullable ? field.SubType : field.Type, value))
                        {
                            _ErrorHandler.HandleError(new CXmlInvalidValueException("Value in %n is not in the range " + field.Ranged +
                                                                                    ". (Value=%v)", node, value.ToString()));
                        }

                        field.SetValue(o, value);
                    }
                }
                //Add embedded lists
                foreach (Tuple <SFieldInfo, List <object> > entry in embLists.Values)
                {
                    _AddList(o, entry.Item1, entry.Item2);
                    fields.Remove(entry.Item1);
                }
            }
            foreach (SFieldInfo field in fields)
            {
                if (!_CheckAndSetDefaultValue(o, field))
                {
                    if (parent != null)
                    {
                        _ErrorHandler.HandleError(new CXmlMissingElementException(parent, field));
                    }
                    object value = _GetValue(null, field.Type, field.ArrayItemName, field.GetValue(o));
                    if (value != null)
                    {
                        field.SetValue(o, value);
                    }
                }
            }
        }
예제 #4
0
 /// <summary>
 ///     Creates a collection (array or list) and puts it into the specified field
 /// </summary>
 /// <param name="o">Object which listField belongs to</param>
 /// <param name="listField">Field that will contain the list</param>
 /// <param name="values">Collection of values that are used to fill the list</param>
 private static void _AddList(object o, SFieldInfo listField, ICollection values)
 {
     listField.SetValue(o, _CreateList(listField.Type, values));
 }
예제 #5
0
 public CXmlMissingElementException(XmlNode parent, SFieldInfo field, bool isError = true) : base("Element: " + field.Name + " is missing in %n", parent, isError)
 {
     Field = field;
 }
예제 #6
0
        /// <summary>
        ///     Fills the struct with information about the field
        /// </summary>
        /// <param name="info">Struct to fill</param>
        /// <param name="field">Field descrived by the struct</param>
        private static void _FillInfo(ref SFieldInfo info, MemberInfo field)
        {
            XmlAttributeAttribute attribute = field.GetAttribute <XmlAttributeAttribute>();

            if (attribute != null)
            {
                info.IsAttribute = true;
                info.Name        = attribute.AttributeName;
            }
            else
            {
                XmlElementAttribute element = field.GetAttribute <XmlElementAttribute>();
                if (element != null)
                {
                    info.Name = element.ElementName;
                }
                else
                {
                    XmlArrayAttribute array = field.GetAttribute <XmlArrayAttribute>();
                    if (array != null)
                    {
                        Debug.Assert(info.Type.IsList() || info.Type.IsArray, "Only lists and arrays can have the array attribute");
                        Debug.Assert(!info.IsAttribute, "Lists cannot be attributes");
                        info.Name   = array.ElementName;
                        info.IsList = true;
                    }
                }
            }
            if (string.IsNullOrEmpty(info.Name))
            {
                info.Name = field.Name;
            }
            XmlAltNameAttribute altName = field.GetAttribute <XmlAltNameAttribute>();

            if (altName != null)
            {
                info.AltName = altName.AltName;
            }

            if (info.Type.IsGenericType)
            {
                info.SubType = info.Type.GetGenericArguments().Last();
            }
            else if (info.Type.IsArray)
            {
                info.SubType = info.Type.GetElementType();
            }
            if (info.Type.IsList() || info.Type.IsArray)
            {
                if (!info.IsList)
                {
                    Debug.Assert(!field.HasAttribute <XmlArrayAttribute>(), "A field cannot have an XmlElement- and XmlArray-Attribute");
                    if (info.Type.IsArray && info.SubType == typeof(byte))
                    {
                        info.IsByteArray = true;
                    }
                    else
                    {
                        info.IsEmbeddedList = true;
                    }
                }
                else
                {
                    XmlArrayItemAttribute arrayItem = field.GetAttribute <XmlArrayItemAttribute>();
                    if (arrayItem != null && !string.IsNullOrEmpty(arrayItem.ElementName))
                    {
                        info.ArrayItemName = arrayItem.ElementName;
                    }
                }
            }
            else if (info.Type.IsNullable())
            {
                info.IsNullable = true;
            }
            else if (info.Type.IsDictionary())
            {
                Debug.Assert(info.Type.GetGenericArguments()[0] == typeof(string), "Keys of dictionaries must be strings");
                info.IsDictionary = true;
            }

            if (field.HasAttribute <XmlNormalizedAttribute>())
            {
                Debug.Assert(info.Type == typeof(float) || (info.IsNullable && info.SubType == typeof(float)), "Only floats can be normalized");
            }
            info.Ranged = field.GetAttribute <XmlRangedAttribute>();
            Type tmpType = info.IsNullable ? info.SubType : info.Type;

            Debug.Assert(info.Ranged == null || tmpType == typeof(int) || tmpType == typeof(float) || tmpType == typeof(double),
                         "Only ints,floats and double can be ranged");

            DefaultValueAttribute defAttr = field.GetAttribute <DefaultValueAttribute>();

            if (defAttr != null)
            {
                Debug.Assert(!info.Type.IsList(), "Lists cannot have a default value");
                info.HasDefaultValue = true;
                info.DefaultValue    = defAttr.Value;
            }
            else if (info.IsNullable)
            {
                info.HasDefaultValue = true;
                info.DefaultValue    = null;
            }
        }