using System.ComponentModel.DataAnnotations.Resources; using System.Diagnostics.CodeAnalysis; using System.Globalization; namespace System.ComponentModel.DataAnnotations { /// /// Allows for clarification of the represented by a given /// property (such as /// or ) /// [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Method | AttributeTargets.Parameter, AllowMultiple = false)] [SuppressMessage("Microsoft.Performance", "CA1813:AvoidUnsealedAttributes", Justification = "We want users to be able to extend this class")] public class DataTypeAttribute : ValidationAttribute { /// /// Gets the DataType. If it equals DataType.Custom, should also be retrieved. /// public DataType DataType { get; private set; } /// /// Gets the string representing a custom data type. Returns a non-null value only if is DataType.Custom. /// public string CustomDataType { get; private set; } /// /// Return the name of the data type, either using the enum or string /// /// The name of the data type enum /// is thrown if the current attribute is ill-formed. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Justification = "This method throws an exception if the properties have not been configured correctly")] public virtual string GetDataTypeName() { this.EnsureValidDataType(); if (DataType == DataType.Custom) { // If it's a custom type string, use it as the template name return this.CustomDataType; } else { // If it's an enum, turn it into a string // Use the cached array with enum string values instead of ToString() as the latter is too slow return _dataTypeStrings[(int)DataType]; } } /// /// Gets the default display format that gets used along with this DataType. /// public DisplayFormatAttribute DisplayFormat { get; protected set; } /// /// Constructor that accepts a data type enumeration /// /// The enum value indicating the type to apply. public DataTypeAttribute(DataType dataType) { DataType = dataType; // Set some DisplayFormat for a few specific data types switch (dataType) { case DataType.Date: this.DisplayFormat = new DisplayFormatAttribute(); this.DisplayFormat.DataFormatString = "{0:d}"; this.DisplayFormat.ApplyFormatInEditMode = true; break; case DataType.Time: this.DisplayFormat = new DisplayFormatAttribute(); this.DisplayFormat.DataFormatString = "{0:t}"; this.DisplayFormat.ApplyFormatInEditMode = true; break; case DataType.Currency: this.DisplayFormat = new DisplayFormatAttribute(); this.DisplayFormat.DataFormatString = "{0:C}"; // Don't set ApplyFormatInEditMode for currencies because the currency // symbol can't be parsed break; } } /// /// Constructor that accepts the string name of a custom data type /// /// The string name of the custom data type. public DataTypeAttribute(string customDataType) : this(DataType.Custom) { this.CustomDataType = customDataType; } /// /// Override of /// /// This override always returns true. Subclasses should override this to provide the correct result. /// The value to validate /// Unconditionally returns true /// is thrown if the current attribute is ill-formed. internal override bool IsValid(object value) { this.EnsureValidDataType(); return true; } /// /// Throws an exception if this attribute is not correctly formed /// /// is thrown if the current attribute is ill-formed. private void EnsureValidDataType() { if (this.DataType == DataType.Custom && String.IsNullOrEmpty(this.CustomDataType)) { throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, DataAnnotationsResources.DataTypeAttribute_EmptyDataTypeString)); } } private static string[] _dataTypeStrings = Enum.GetNames(typeof(DataType)); } }