| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141 | 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 Caption { get; set; }        bool IsCalculated { 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; }        Expression Expression();        Func<object, object> Getter();        Action<object, object?> Setter();        TAttribute? GetAttribute<TAttribute>() where TAttribute : Attribute;    }    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;        }    }}
 |