Использование атрибутов для нормализации и валидации бизнес-сущностей - Базовый класс для атрибутов валидации
ОГЛАВЛЕНИЕ
Страница 6 из 6
А теперь напишем аналогичный базовый класс для атрибутов валидации.
/// <summary>также напишем сортировщик (по аналогии с нормализацией) и несколько атрибутов валидации (их код можно найти в прилагаемом архиве)
/// Базовый класс-атрибут для создания атрибутов валидации
/// </summary>
[AttributeUsage(AttributeTargets.Property)]
public abstract class ValidationBaseAttribute : Attribute
{
int m_validationOrder = 0;
/// <summary>
/// Порядок проведения валидации
/// </summary>
public virtual int ValidationOrder
{
get {return m_validationOrder;}
}
WarningLevel m_level = WarningLevel.Warning;
/// <summary>
/// Уровень предупреждения
/// </summary>
public virtual WarningLevel Level
{
get {return m_level;}
set {m_level = value;}
}
/// <summary>
/// Базовый атрибут валидации
/// </summary>
/// <param name="validationOrder">Порядковый номер в процессе валидации</param>
public ValidationBaseAttribute(int validationOrder)
{
m_validationOrder = validationOrder;
}
/// <summary>
/// Произвести валидацию
/// </summary>
/// <param name="value">значение для проверки</param>
/// <returns>Строку с предупреждением, либо пустую строку если всё в порядке</returns>
public virtual string Validate(object value)
{
return "#ValidationBase - Validate method not overrided!";
}
}
- ValidationEmptyAttribute (Атрибут проверки свойства на пустоту (null, DBNull, string.empty, (int)0))
- ValidationStringLengthAttribute (Атрибут проверки свойства на длину строки (может применяться несколько раз))
- ValidationIntValueAttribute (Атрибут проверки свойства на значение целочисленного типа (может применяться несколько раз))
- ValidationCollectionEmptyAttribute (Атрибут проверки свойства на пустоту коллекции (списка))
- ValidationDateYearRangeAttribute (Атрибут проверки свойства на нахождение года даты в указанных пределах (может применяться несколько раз))
Напишем достаточно несложный код проверки. Он получает список всех свойств объекта, для каждого свойства запрашивается список атрибутов, дочерних для ValidationBaseAttribute. Затем вызывается виртуальный (переопределенный в дочерних классах) метод Validate который возвращает пустую строку, если предупреждений не было или строку сообщения в противном случае. Полученную строку сообщения мы добавляем в словарь (Hashtable)
/// <summary>В строчке //additional можно добавить вызовы собственных, комплексных функций проверки введенных данных, определенных в этом же классе. Словарь возвращенных предупреждений мы выводим в диалоговом окне в виде списка, чтобы пользователь мог с ними ознакомиться (или в данном случае в консоль).
/// Проверить объект на соответствие установленным ограничениям
/// </summary>
/// <returns>Словарь найденных несоответствий</returns>
public IDictionary Validate()
{
IDictionary result = new Hashtable();
// Получить атрибуты уровня свойств.
// Получить все свойства данного класса и поместить их в массив
PropertyInfo[] pInfo = this.GetType().GetProperties();
// атрибуты всех свойств класса
for (int j=0; j<pInfo.Length; j++)
{
Attribute[] atts = Attribute.GetCustomAttributes(pInfo[j], typeof(ValidationBaseAttribute));
if (atts.Length == 0)
continue;
Array.Sort(atts, new ValidationComparer());
string _fieldName = pInfo[j].Name;
Attribute dna = Attribute.GetCustomAttribute(pInfo[j], typeof(DisplayNameAttribute));
if (dna != null)
_fieldName = ((DisplayNameAttribute)dna).Name;
for (int k=0; k<atts.Length; k++)
{
ValidationBaseAttribute att = (ValidationBaseAttribute)atts[k];
if (att != null)
{
string vr = att.Validate(pInfo[j].GetValue(this, null));
if (vr != "")
{
result.Add(_fieldName +": "+ vr, att.Level);
//если ошибка - прекратить проверку данного поля
if (att.Level == WarningLevel.Error)
break;
}
}
}
}
//additional :(
return result;
}
и результаты выполнения следующего кода
/// <summary>Итак, несмотря на некоторые недостатки, данный подход имеет право на существование.
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
Person p = new Person(-1);
p.ShowNames();
Console.ReadLine();
p.Name = " Иванов Иван Иванович ";
Console.WriteLine("'{0}'", p.Name);
p.Normalize();
Console.WriteLine("'{0}'", p.Name);
Console.ReadLine();
<b>p.Validate();</b>
Console.ReadLine();
}