public object Clone(object source)
        {
            object clone = source;

            foreach (PropertyInfo item in source.GetType().GetProperties())
            {
                CloneableAttribute[] cloneAttr = (CloneableAttribute[])item.GetCustomAttributes(typeof(CloneableAttribute), true);

                CloneableAttribute attr = null;
                if (cloneAttr.Length != 1)
                {
                    attr = new CloneableAttribute(CloningMode.Deep);
                }
                else
                {
                    attr = cloneAttr[0];
                };

                switch (attr.Mode)
                {
                case CloningMode.Ignore:
                    PropertyInfo prop = clone.GetType().GetProperty(item.Name);
                    if (prop.GetType().IsValueType)
                    {
                        prop.SetValue(clone, 0);
                    }
                    else
                    {
                        prop.SetValue(clone, null);
                    }
                    break;

                case CloningMode.Shallow:
                    break;

                case CloningMode.Deep:
                    PropertyInfo deepProp = clone.GetType().GetProperty(item.Name);
                    using (MemoryStream stream = new MemoryStream())
                    {
                        if (source.GetType().IsSerializable)
                        {
                            BinaryFormatter formatter = new BinaryFormatter();
                            formatter.Serialize(stream, this);
                            stream.Position = 0;
                            deepProp.SetValue(clone, formatter.Deserialize(stream));
                        }
                    }
                    break;
                }
            }

            return(clone);
        }
        public T Clone <T>(T source)
        {
            T clone = Activator.CreateInstance <T>();

            foreach (PropertyInfo item in source.GetType().GetProperties())
            {
                CloneableAttribute[] cloneAttr = (CloneableAttribute[])item.GetCustomAttributes(typeof(CloneableAttribute), true);

                CloneableAttribute attr = null;
                if (cloneAttr.Length != 1)
                {
                    attr = new CloneableAttribute(CloningMode.Deep);
                }
                else
                {
                    attr = cloneAttr[0];
                };
                if (item.GetValue(source) == null)
                {
                    attr = new CloneableAttribute(CloningMode.Ignore);
                }
                ;

                switch (attr.Mode)
                {
                case CloningMode.Ignore:
                    PropertyInfo prop = clone.GetType().GetProperty(item.Name);
                    prop.SetValue(clone, null);
                    break;

                case CloningMode.Shallow:
                    PropertyInfo shallowProp = clone.GetType().GetProperty(item.Name);
                    shallowProp.SetValue(clone, item.GetValue(source));
                    break;

                case CloningMode.Deep:
                    PropertyInfo deepProp = clone.GetType().GetProperty(item.Name);
                    using (MemoryStream stream = new MemoryStream())
                    {
                        BinaryFormatter formatter = new BinaryFormatter();
                        formatter.Serialize(stream, item.GetValue(source));
                        stream.Seek(0, SeekOrigin.Begin);
                        deepProp.SetValue(clone, formatter.Deserialize(stream));
                        stream.Close();
                    }
                    break;
                }
            }

            return(clone);
        }