| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162 | using System;using System.Linq.Expressions;using System.Runtime.CompilerServices;namespace InABox.Core{    public interface IProperty    {        string Class { get; set; }        Type? ClassType { get; set; }        string Name { get; set; }        string Type { get; set; }        Type PropertyType { get; set; }        string Page { get; set; }        /// <summary>        /// Whether the property or any parents actually declares an editor.        /// </summary>        /// <remarks>        /// If <c>false</c>, <see cref="Editor"/> will be a <see cref="NullEditor"/>.        /// </remarks>        bool HasEditor { get; set; }        BaseEditor Editor { get; set; }        long Sequence { get; set; }        string Comment { get; set; }        string Caption { get; set; }        bool IsCalculated { get; }        bool IsPersistable { get; }        bool IsSerializable { get; }        /// <summary>        /// Returns <see langword="true"/> if this is a column to be stored in a database table.        /// </summary>        /// <remarks>        /// This is equivalent to the property being a <see cref="CustomProperty"/> or a <see cref="StandardProperty"/> which        /// is non-calculated, persistable, writeable and is a <i>local property</i>.        /// </remarks>        bool IsDBColumn { get; }        /// <summary>        /// An <see cref="IProperty"/> is required if it has the <see cref="RequiredColumnAttribute"/> defined on it.<br/>        /// If it is part of an <see cref="IEntityLink"/>, then it is only required if the <see cref="IEntityLink"/> property on the parent class        /// also has <see cref="RequiredColumnAttribute"/>.        /// </summary>        bool Required { get; set; }        /// <summary>        /// Null if the <see cref="IProperty"/> is not loggable.<br/>        /// An <see cref="IProperty"/> is loggable if it has the <see cref="LoggablePropertyAttribute"/> defined on it.<br/>        /// If it is part of an <see cref="IEntityLink"/>, then it is only loggable if the <see cref="IEntityLink"/> property on the parent class        /// also has <see cref="LoggablePropertyAttribute"/>.        /// </summary>        LoggablePropertyAttribute? Loggable { get; set; }        IProperty? Parent { get; set; }        bool IsEntityLink { get; set; }        bool IsEnclosedEntity { get; set; }        bool IsParent { get; set; }        Expression Expression();        Func<object, object> Getter();        internal Func<object, object> NullSafeGetter();        Action<object, object?> Setter();        TAttribute? GetAttribute<TAttribute>() where TAttribute : Attribute;        decimal PropertySequence();    }    public static class PropertyExtensions    {        public static bool HasAttribute<TAttribute>(this IProperty property) where TAttribute : Attribute            => property.GetAttribute<TAttribute>() != null;        /// <summary>        /// Get the outermost parent property which has an editor.        /// </summary>        /// <param name="property"></param>        /// <returns></returns>        public static IProperty? GetParentWithEditor(this IProperty property)        {            if (property.Parent == null) return null;            var parent = property.Parent.GetParentWithEditor();            if (parent != null) return parent;            if (property.Parent.HasEditor)            {                return property.Parent;            }            return null;        }        /// <summary>        /// Gets the outermost parent property which matches the predicate.        /// </summary>        /// <param name="property"></param>        /// <param name="predicate"></param>        /// <returns></returns>        public static IProperty? GetOuterParent(this IProperty property, Func<IProperty, bool> predicate)        {            if (property.Parent == null) return null;            return property.Parent.GetOuterParent(predicate)                ?? (predicate(property.Parent) ? property.Parent : null);        }        /// <summary>        /// Gets the innermost parent property which matches the predicate.        /// </summary>        /// <param name="property"></param>        /// <param name="predicate"></param>        /// <returns></returns>        public static IProperty? GetParent(this IProperty property, Func<IProperty, bool> predicate)        {            if (property.Parent == null) return null;            if(predicate(property.Parent)) return property.Parent;            return property.Parent.GetParent(predicate);        }        public static bool HasParentEditor(this IProperty property)        {            return property.Parent != null && (property.Parent.HasEditor || property.Parent.HasParentEditor());        }        public static bool HasParentEntityLink(this IProperty property)        {            return property.Parent != null && (property.Parent.IsEntityLink || property.Parent.HasParentEntityLink());        }        public static bool ShouldShowEditor(this IProperty property)        {            if (property.Parent == null)                return true;            if (property.HasParentEditor())                return false;            if (property.Parent.IsEntityLink && !property.Name.EndsWith(".ID"))                return false;            if (property.Parent.HasParentEntityLink())                return false;            return true;        }    }}
 |