Setting the default value of a DateTime Property to DateTime.Now inside the System.ComponentModel Default Value Attrbute

后端 未结 21 1444
终归单人心
终归单人心 2020-11-29 22:53

Does any one know how I can specify the Default value for a DateTime property using the System.ComponentModel DefaultValue Attribute?

for example I try this:

21条回答
  •  北荒
    北荒 (楼主)
    2020-11-29 23:14

    There is a way. Add these classes:

    DefaultDateTimeValueAttribute.cs

    using System;
    using System.ComponentModel;
    using System.ComponentModel.DataAnnotations;
    using System.Linq;
    using System.Reflection;
    using System.Runtime.CompilerServices;
    using Custom.Extensions;
    
    namespace Custom.DefaultValueAttributes
    {
        /// 
        /// This class's DefaultValue attribute allows the programmer to use DateTime.Now as a default value for a property.
        /// Inspired from https://code.msdn.microsoft.com/A-flexible-Default-Value-11c2db19. 
        /// 
        [AttributeUsage(AttributeTargets.Property)]
        public sealed class DefaultDateTimeValueAttribute : DefaultValueAttribute
        {
            public string DefaultValue { get; set; }
            private object _value;
    
            public override object Value
            {
                get
                {
                    if (_value == null)
                        return _value = GetDefaultValue();
    
                    return _value;
                }
            }
    
            /// 
            /// Initialized a new instance of this class using the desired DateTime value. A string is expected, because the value must be generated at runtime.
            /// Example of value to pass: Now. This will return the current date and time as a default value. 
            /// Programmer tip: Even if the parameter is passed to the base class, it is not used at all. The property Value is overridden.
            /// 
            /// Default value to render from an instance of 
            public DefaultDateTimeValueAttribute(string defaultValue) : base(defaultValue)
            {
                DefaultValue = defaultValue;
            }
    
            public static DateTime GetDefaultValue(Type objectType, string propertyName)
            {
                var property = objectType.GetProperty(propertyName);
                var attribute = property.GetCustomAttributes(typeof(DefaultDateTimeValueAttribute), false)
                    ?.Cast()
                    ?.FirstOrDefault();
    
                return attribute.GetDefaultValue();
            }
    
            private DateTime GetDefaultValue()
            {
                // Resolve a named property of DateTime, like "Now"
                if (this.IsProperty)
                {
                    return GetPropertyValue();
                }
    
                // Resolve a named extension method of DateTime, like "LastOfMonth"
                if (this.IsExtensionMethod)
                {
                    return GetExtensionMethodValue();
                }
    
                // Parse a relative date
                if (this.IsRelativeValue)
                {
                    return GetRelativeValue();
                }
    
                // Parse an absolute date
                return GetAbsoluteValue();
            }
    
            private bool IsProperty
                => typeof(DateTime).GetProperties()
                    .Select(p => p.Name).Contains(this.DefaultValue);
    
            private bool IsExtensionMethod
                => typeof(DefaultDateTimeValueAttribute).Assembly
                    .GetType(typeof(DefaultDateTimeExtensions).FullName)
                    .GetMethods()
                    .Where(m => m.IsDefined(typeof(ExtensionAttribute), false))
                    .Select(p => p.Name).Contains(this.DefaultValue);
    
            private bool IsRelativeValue
                => this.DefaultValue.Contains(":");
    
            private DateTime GetPropertyValue()
            {
                var instance = Activator.CreateInstance();
                var value = (DateTime)instance.GetType()
                    .GetProperty(this.DefaultValue)
                    .GetValue(instance);
    
                return value;
            }
    
            private DateTime GetExtensionMethodValue()
            {
                var instance = Activator.CreateInstance();
                var value = (DateTime)typeof(DefaultDateTimeValueAttribute).Assembly
                    .GetType(typeof(DefaultDateTimeExtensions).FullName)
                    .GetMethod(this.DefaultValue)
                    .Invoke(instance, new object[] { DateTime.Now });
    
                return value;
            }
    
            private DateTime GetRelativeValue()
            {
                TimeSpan timeSpan;
                if (!TimeSpan.TryParse(this.DefaultValue, out timeSpan))
                {
                    return default(DateTime);
                }
    
                return DateTime.Now.Add(timeSpan);
            }
    
            private DateTime GetAbsoluteValue()
            {
                DateTime value;
                if (!DateTime.TryParse(this.DefaultValue, out value))
                {
                    return default(DateTime);
                }
    
                return value;
            }
        }
    }
    

    DefaultDateTimeExtensions.cs

    using System;
    
    namespace Custom.Extensions
    {
        /// 
        /// Inspired from https://code.msdn.microsoft.com/A-flexible-Default-Value-11c2db19. See usage for more information.
        /// 
        public static class DefaultDateTimeExtensions
        {
            public static DateTime FirstOfYear(this DateTime dateTime)
                => new DateTime(dateTime.Year, 1, 1, dateTime.Hour, dateTime.Minute, dateTime.Second, dateTime.Millisecond);
    
            public static DateTime LastOfYear(this DateTime dateTime)
                => new DateTime(dateTime.Year, 12, 31, dateTime.Hour, dateTime.Minute, dateTime.Second, dateTime.Millisecond);
    
            public static DateTime FirstOfMonth(this DateTime dateTime)
                => new DateTime(dateTime.Year, dateTime.Month, 1, dateTime.Hour, dateTime.Minute, dateTime.Second, dateTime.Millisecond);
    
            public static DateTime LastOfMonth(this DateTime dateTime)
                => new DateTime(dateTime.Year, dateTime.Month, DateTime.DaysInMonth(dateTime.Year, dateTime.Month), dateTime.Hour, dateTime.Minute, dateTime.Second, dateTime.Millisecond);
        }
    }
    

    And use DefaultDateTimeValue as an attribute to your properties. Value to input to your validation attribute are things like "Now", which will be rendered at run time from a DateTime instance created with an Activator. The source code is inspired from this thread: https://code.msdn.microsoft.com/A-flexible-Default-Value-11c2db19. I changed it to make my class inherit with DefaultValueAttribute instead of a ValidationAttribute.

提交回复
热议问题