Я опубликую это как другой ответ, потому что он характерно отличается от кодовых контрактов.
Один из подходов, который вы можете использовать для декларативной проверки, - это использование словаря или хеш-таблицы в качестве хранилища свойств,и поделитесь утилитарным методом для проверки.
Например:
// Example attribute class for MaxStringLength
public class MaxStringLengthAttribute : Attribute
{
public int MaxLength { get; set; }
public MaxStringLengthAttribute(int length) { this.MaxLength = length; }
}
// Class using the dictionary store and shared validation routine.
public class MyDataClass
{
private Hashtable properties = new Hashtable();
public string CompanyName
{
get { return GetValue<string>("CompanyName"); }
[MaxStringLength(50)]
set { SetValue<string>("CompanyName", value); }
}
public TResult GetValue<TResult>(string key)
{
return (TResult)(properties[key] ?? default(TResult));
}
public void SetValue<TValue>(string key, TValue value)
{
// Example retrieving attribute:
var attributes = new StackTrace()
.GetFrame(1)
.GetMethod()
.GetCustomAttributes(typeof(MaxStringLengthAttribute), true);
// With the attribute in hand, perform validation here...
properties[key] = value;
}
}
Вы можете получить свойство вызова с помощью отражения, обработав трассировку стека, как продемонстрировано здесь .Отразите атрибуты свойств, запустите проверку и вуаля! Однострочные геттеры / установщики, которые разделяют общую процедуру проверки.
Кроме этого, этот шаблон также удобен, поскольку вы можете разработатькласс для использования альтернативных словарных хранилищ свойств, таких как ViewState или Session (в ASP.NET) , путем обновления только GetValue
и SetValue
.
Еще одно примечаниеЕсли вы используете этот подход, вы можете рассмотреть реорганизацию логики валидации в класс утилиты валидации для совместного использования всеми вашими типами.Это должно помочь предотвратить слишком большой объем вашего класса данных в методе SetValue
.