Click here to Skip to main content
15,891,184 members
Articles / Multimedia / GDI+

Drawing Library

Rate me:
Please Sign up or sign in to vote.
4.78/5 (63 votes)
10 Dec 2007CPOL3 min read 293.7K   12.8K   211  
A library for creating shapes and developing tools.
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using System.Reflection;
using System.Collections.ObjectModel;

namespace Globe.Xml.Serialization
{
    /// <summary>
    /// Builds a SerializableData from a SerializableData.
    /// </summary>
    public class SerializableDataDecomposer : SerializableDataController
    {
        #region Constructors

        /// <summary>
        /// Default constructor.
        /// </summary>
        public SerializableDataDecomposer()
        {
        }

        #endregion

        #region Public Functions

        /// <summary>
        /// Checks if the passed data is serializable and if it is decomposing the data.
        /// </summary>
        /// <param name="data">Data to serialize.</param>
        virtual public void Decompose(object data)
        {
            if (data == null)
                throw new XmlSerializationException(data, null);

            FindXmlSerializableClassAttribute(data, SerializableDataInfo);
        }

        #endregion

        #region Protected Functions

        /// <summary>
        /// Finds the XmlClassSerializable attribute of the data and fill the SerializableData.
        /// </summary>
        /// <param name="data">Data to serialize.</param>
        /// <param name="serializableData">SerializableData to fill with found attributes.</param>
        virtual protected bool FindXmlSerializableClassAttribute(object data, SerializableData serializableData)
        {
            Type type = data.GetType();
            XmlClassSerializable attribute = GetXmlClassSerializableAttribute(type);
            if (attribute == null)
                return false;

            CreateSerializableData(data, serializableData);

            Collection<DataMember> dataMembers = new Collection<DataMember>();

            FillDataMembers(type, dataMembers, true, attribute.Deep, GetFlags(type, attribute));
            FindClassFields(data, serializableData, dataMembers);

            return true;
        }

        /// <summary>
        /// If the data derives from System.Collections.ICollection, it fills serializableData.
        /// Can override this function to customize the filling in a user collection.
        /// </summary>
        /// <param name="data">Data to check.</param>
        /// <param name="serializableData">SerializableData to fill.</param>
        virtual protected bool FillCollection(object data, SerializableData serializableData)
        {
            if (!IsCollection(data))
                return false;

            System.Collections.ICollection collection = data as System.Collections.ICollection;

            foreach (object internalData in collection)
            {
                SerializableData newSerializableData = new SerializableData();

                XmlClassSerializable attribute = GetXmlClassSerializableAttribute(internalData.GetType());

                if (!FindXmlSerializableClassAttribute(internalData, newSerializableData))
                {
                    Type type = internalData.GetType();

                    Collection<DataMember> dataMembers = new Collection<DataMember>();

                    FillDataMembers(type, dataMembers, false, IsDeepSerializable(type), GetFlags(type, attribute));
                    if (dataMembers.Count == 0)
                        continue;

                    CreateSerializableData(internalData, newSerializableData);
                    FindClassFields(internalData, newSerializableData, dataMembers);
                }

                serializableData.SerializableDataCollection.Add(newSerializableData);
            }

            return true;
        }

        /// <summary>
        /// Recursive filling of dataMembers.
        /// </summary>
        /// <param name="type">Type to check.</param>
        /// <param name="dataMembers">DataMember collection to fill.</param>
        /// <param name="custom">Filtering with custom serialize attributes.</param>
        /// <param name="deep">Deep filling in the hierarchy.</param>
        /// <param name="flags">Flags to specified the filling members type.</param>
        virtual protected void FillDataMembers(Type type, Collection<DataMember> dataMembers, bool custom, bool deep, BindingFlags flags)
        {
            MemberInfo[] members = type.FindMembers(MemberTypes.Field | MemberTypes.Property, flags, custom ? new MemberFilter(CustomSearching) : new MemberFilter(Searching), dataMembers);

            if (!type.BaseType.Equals(typeof(object)) && !type.BaseType.Equals(typeof(ValueType)) && type.BaseType != null && deep)
                FillDataMembers(type.BaseType, dataMembers, custom, deep, flags);
        }

        /// <summary>
        /// Adds a DataMember to dataMembers.
        /// </summary>
        /// <param name="memberInfo">MemberInfo used to create a DataMember.</param>
        /// <param name="dataMembers">DataMember collection to fill.</param>
        /// <returns>True if the MemberInfo is inserted.</returns>
        virtual protected bool FillDataMembers(MemberInfo memberInfo, Collection<DataMember> dataMembers)
        {
            if (memberInfo.MemberType == MemberTypes.Field)
            {
                FieldInfo fieldInfo = (FieldInfo)memberInfo;

                DataMember dataMember = new DataMember(memberInfo, fieldInfo.FieldType);
                dataMembers.Add(dataMember);

                return true;
            }
            else if (memberInfo.MemberType == MemberTypes.Property)
            {
                PropertyInfo propertyInfo = (PropertyInfo)memberInfo;

                DataMember dataMember = new DataMember(memberInfo, propertyInfo.PropertyType);
                dataMembers.Add(dataMember);
    
                return true;
            }

            return false;
        }

        /// <summary>
        /// Function called by FillDataMembers for custom serializable attribute.
        /// </summary>
        /// <param name="memberInfo">Reference MemberInfo.</param>
        /// <param name="dataMembersFinder">DataMember collection to fill.</param>
        /// <returns>True if the field if found.</returns>
        virtual protected bool CustomSearching(MemberInfo memberInfo, object dataMembersFinder)
        {
            Collection<DataMember> dataMembers = dataMembersFinder as Collection<DataMember>;
            if (dataMembers == null)
                return false;

            if (memberInfo.GetCustomAttributes(typeof(XmlFieldSerializable), true).GetLength(0) != 1)
                return false;

            // Checks if a DataMember in the hierarhy of classes is just inserted in the collection
            foreach (DataMember dataMember in dataMembers)
                if (dataMember.DataInfo.ToString() == memberInfo.ToString())
                    return false;

            return FillDataMembers(memberInfo, dataMembers);
        }

        /// <summary>
        /// Fills DataMember collection.
        /// </summary>
        /// <param name="memberInfo">Reference DataMember.</param>
        /// <param name="dataMembersFinder">DataMember collection to fill.</param>
        /// <returns>True if the field if found.</returns>
        virtual protected bool Searching(MemberInfo memberInfo, object dataMembersFinder)
        {
            Collection<DataMember> dataMembers = dataMembersFinder as Collection<DataMember>;
            if (dataMembers == null)
                return false;

            return FillDataMembers(memberInfo, dataMembers);
        }

        /// <summary>
        /// Finds the XmlClassSerializable attribute of the data.
        /// </summary>
        /// <param name="data">Data in which searching.</param>
        /// <param name="serializableData">Reference SerializableData.</param>
        /// <param name="dataMembers">Data mebers</param>
        virtual protected void FindClassFields(object data, SerializableData serializableData, Collection<DataMember> dataMembers)
        {
            Type type = data.GetType();
            
            for (int i = 0; i < dataMembers.Count; i++)
            {
                SerializableData newSerializableData = new SerializableData();

                if (GetXmlClassSerializableAttribute(dataMembers[i].TypeInfo) != null)
                {
                    object field = type.InvokeMember(dataMembers[i].DataInfo.Name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance | BindingFlags.GetField | BindingFlags.GetProperty, null, data, null);
                    newSerializableData.FieldName = dataMembers[i].DataInfo.Name;

                    if (!FindXmlSerializableClassAttribute(field, newSerializableData))
                        continue;
                }
                else
                {
                    newSerializableData = CreateSerializableData(data, dataMembers[i]);
                    if (newSerializableData == null)
                        continue;
                }

                serializableData.SerializableDataCollection.Add(newSerializableData);
            }

            FillCollection(data, serializableData);
        }

        /// <summary>
        /// Create a SerializableData from an object and a DataMember.
        /// </summary>
        /// <param name="data">Reference data.</param>
        /// <param name="dataMember">Reference DataMember.</param>
        /// <returns>New SerializableData.</returns>
        virtual protected SerializableData CreateSerializableData(object data, DataMember dataMember)
        {
            bool foundAttribute = true;

            XmlFieldSerializable attribute = GetXmlFieldSerializableAttribute(dataMember.DataInfo);
            if (attribute == null || attribute.TagName == string.Empty)
                foundAttribute = false;

            object value = null;
            SerializableData newSerializableData = new SerializableData();
            BindingFlags flags = GetFlags(data.GetType());

            PropertyInfo property = GetProperty(dataMember.DataInfo.ReflectedType, dataMember.DataInfo.Name, flags);
            if (property != null && property.CanRead)
                value = property.GetGetMethod(true).Invoke(data, null);
            else
            {
                FieldInfo field = GetField(dataMember.DataInfo.ReflectedType, dataMember.DataInfo.Name, flags);
                if (field != null)
                    value = field.GetValue(data);
                    //value = dataMember.DataInfo.ReflectedType.InvokeMember(dataMember.DataInfo.Name, flags, null, data, null);
                else
                    return null;
            }

            newSerializableData.Type = dataMember.TypeInfo.FullName;
            newSerializableData.Assembly = dataMember.TypeInfo.Assembly.ToString();
            newSerializableData.AssemblyQualifiedName = dataMember.TypeInfo.AssemblyQualifiedName;
            newSerializableData.Value = value != null ? value.ToString() : string.Empty;
            newSerializableData.TagName = foundAttribute ? attribute.TagName : dataMember.TypeInfo.Name;
            newSerializableData.FieldName = dataMember.DataInfo.Name;

            FillCollection(value, newSerializableData);

            return newSerializableData;
        }

        /// <summary>
        /// Create a SerializableData from an object. FieldName will be empty.
        /// </summary>
        /// <param name="data">Reference Data.</param>
        /// <param name="serializableData">new SerializableData.</param>
        virtual protected void CreateSerializableData(object data, SerializableData serializableData)
        {
            Type type = data.GetType();

            bool foundAttribute = true;
            XmlClassSerializable attribute = GetXmlClassSerializableAttribute(type);
            if (attribute == null || attribute.TagName == string.Empty)
                foundAttribute = false;

            serializableData.Type = type.FullName;
            serializableData.Assembly = type.Assembly.ToString();
            serializableData.AssemblyQualifiedName = type.AssemblyQualifiedName;
            serializableData.Value = foundAttribute ? string.Empty : data.ToString();
            serializableData.TagName = foundAttribute ? attribute.TagName : type.Name;
        }

        /// <summary>
        /// Returns binding flags.
        /// </summary>
        /// <param name="type">Type to check.</param>
        /// <param name="attribute">Type to check.</param>
        /// <returns>Binding flags.</returns>
        protected override BindingFlags GetFlags(Type type, XmlClassSerializable attribute)
        {
            BindingFlags flags = base.GetFlags(type, attribute);
            flags |= BindingFlags.GetField | BindingFlags.GetProperty;

            return flags;
        }

        #endregion
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
Italy Italy
I am a biomedical engineer. I work in Genoa as software developer. I developed MFC ActiveX controls for industrial automation for 2 years and packages for Visual Studio 2005 for 1 year. Currently I'm working in .NET 3.5 in biomedical area.

Comments and Discussions