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));
}
}