На самом деле это подмножество вопроса как получить экземпляр, оформленный атрибутом, из атрибута (аналогичный вопрос здесь ).
К сожалению, короткий ответ: вы не можете.
Атрибуты являются метаданными. Атрибут не знает и не может знать что-либо о классе или члене, который он украшает. Кто-то из нижестоящих потребителей этого класса должен найти указанные пользовательские атрибуты и решить, следует ли / когда / как их применять.
Вы должны думать об атрибутах как данные , а не объекты . Хотя атрибуты технически являются классами, они довольно глупы, потому что имеют критическое ограничение: все в них должно быть определено во время компиляции. Это фактически означает, что они не могут получить доступ к какой-либо информации времени выполнения, если не предоставят метод, который принимает экземпляр времени выполнения и , когда вызывающая сторона решит вызвать его.
Вы могли бы сделать последнее. Вы можете создать свой собственный атрибут, и, пока вы контролируете валидатор, вы можете заставить валидатор вызывать какой-либо метод для атрибута и заставлять его делать что угодно:
public abstract class CustomValidationAttribute : Attribute
{
// Returns the error message, if any
public abstract string Validate(object instance);
}
Пока тот, кто использует этот класс, правильно использует атрибут, это будет работать:
public class MyValidator
{
public IEnumerable<string> Validate(object instance)
{
if (instance == null)
throw new ArgumentNullException("instance");
Type t = instance.GetType();
var validationAttributes = (CustomValidationAttribute[])Attribute
.GetCustomAttributes(t, typeof(CustomValidationAttribute));
foreach (var validationAttribute in validationAttributes)
{
string error = validationAttribute.Validate(instance);
if (!string.IsNullOrEmpty(error))
yield return error;
}
}
}
Если именно так вы потребляете атрибутов, реализовать свои собственные становится просто:
public class PasswordValidationAttribute : CustomValidationAttribute
{
public override string Validate(object instance)
{
ChangePasswordModel model = instance as ChangePasswordModel;
if (model == null)
return null;
if (model.NewPassword != model.ConfirmPassword)
return Resources.GetLocalized("PasswordsDoNotMatch");
return null;
}
}
Это все хорошо и просто, просто поток управления инвертирован по сравнению с тем, который вы указали в исходном вопросе. Атрибут ничего не знает о том, к чему он был применен; валидатор, который использует , атрибут должен предоставить эту информацию (что он может легко сделать).
Конечно, это не то, как валидация на самом деле работает с аннотациями данных в MVC 2 (если только она не сильно изменилась со времени моего последнего просмотра). Я не думаю, что вы сможете просто подключить это с ValidationMessageFor
и другими подобными функциями. Но в MVC 1 мы все равно должны были написать все наши валидаторы. Вам ничто не помешает объединить DataAnnotations с вашими собственными атрибутами проверки и валидаторами, просто потребуется немного больше кода. Вам придется вызывать ваш специальный валидатор везде, где вы пишете код валидации.
Возможно, это не тот ответ, который вы ищете, но, к сожалению, так оно и есть; атрибут валидации не может знать о классе, к которому он был применен, если только эта информация не предоставлена самим валидатором.