/// <summary>
        /// Method to assign the value of one type to another
        /// </summary>
        /// <param name="from">Other object</param>
        public void Assign(ModelObject from)
        {
            // Assigning null values is not supported
            if (from == null)
            {
                throw new ArgumentNullException(nameof(from));
            }

            // Validate the types
            Type myType = GetType();

            if (from.GetType() != myType)
            {
                throw new ArgumentException("Types do not match", nameof(from));
            }

            // Assign property values
            foreach (PropertyInfo property in GetType().GetProperties())
            {
                if (property.PropertyType.IsSubclassOf(typeof(ModelObject)))
                {
                    ModelObject oldValue = (ModelObject)property.GetValue(this);
                    ModelObject newValue = (ModelObject)property.GetValue(from);
                    if (oldValue == null || newValue == null)
                    {
                        property.SetValue(this, newValue);
                    }
                    else if (oldValue.GetType() != newValue.GetType())
                    {
                        property.SetValue(this, newValue.Clone());
                    }
                    else
                    {
                        oldValue.Assign(newValue);
                    }
                }
                else if (ModelCollection.GetItemType(property.PropertyType, out Type itemType))
                {
                    IList oldModelCollection = (IList)property.GetValue(this);
                    IList newModelCollection = (IList)property.GetValue(from);
                    if (ModelGrowingCollection.TypeMatches(property.PropertyType))
                    {
                        ModelGrowingCollectionHelper.Assign(oldModelCollection, newModelCollection);
                    }
                    else
                    {
                        ModelCollectionHelper.Assign(oldModelCollection, itemType, newModelCollection);
                    }
                }
                else
                {
                    object newValue = property.GetValue(from);
                    property.SetValue(this, newValue);
                }
            }
        }
        /// <summary>
        /// Create a clone of this instance
        /// </summary>
        /// <returns>Cloned object</returns>
        public object Clone()
        {
            // Make a new clone
            Type        myType = GetType();
            ModelObject clone  = (ModelObject)Activator.CreateInstance(myType);

            // Assign cloned property values
            foreach (PropertyInfo property in GetType().GetProperties())
            {
                if (property.PropertyType.IsSubclassOf(typeof(ModelObject)))
                {
                    ModelObject value      = (ModelObject)property.GetValue(this);
                    ModelObject cloneValue = (ModelObject)property.GetValue(clone);
                    if (value == null || cloneValue == null)
                    {
                        property.SetValue(clone, value);
                    }
                    else if (value.GetType() != cloneValue.GetType())
                    {
                        property.SetValue(clone, value.Clone());
                    }
                    else
                    {
                        cloneValue.Assign(value);
                    }
                }
                else if (ModelCollection.GetItemType(property.PropertyType, out Type itemType))
                {
                    IList collection       = (IList)property.GetValue(this);
                    IList clonedCollection = (IList)property.GetValue(clone);
                    if (ModelGrowingCollection.TypeMatches(property.PropertyType))
                    {
                        ModelGrowingCollectionHelper.Assign(clonedCollection, collection);
                    }
                    else
                    {
                        ModelCollectionHelper.Assign(clonedCollection, itemType, collection);
                    }
                }
                else if (property.PropertyType.IsAssignableFrom(typeof(ICloneable)))
                {
                    ICloneable value = (ICloneable)property.GetValue(this);
                    property.SetValue(clone, value?.Clone());
                }
                else
                {
                    object value = property.GetValue(this);
                    property.SetValue(clone, value);
                }
            }

            return(clone);
        }