Так вот как я это решил. Во-первых, основной класс ValidationResult выглядит так:
public class ValidationResult
{
public List<ValidationResultItem> ValidationResultItems { get; set; }
public bool IsAcceptable
{
get { return (ValidationResultItems == null || !ValidationResultItems.Any(vri => !vri.IsAcceptable)); }
}
public void Add(ValidationResultItem propertyValidationResultItem)
{
ValidationResultItems.Add(propertyValidationResultItem);
}
public void Add(IEnumerable<ValidationResultItem> validationResultItems)
{
ValidationResultItems.AddRange(validationResultItems);
}
}
ValidationResultItem - абстрактный класс:
public abstract class ValidationResultItem
{
private ResultType _resultType;
protected ValidationResultItem(ResultType resultType, string message)
{
ResultType = resultType;
Message = message;
}
public bool IsAcceptable { get; private set; }
public string Message { get; private set; }
public ResultType ResultType
{
get { return _resultType; }
set { _resultType = value; IsAcceptable = (_resultType != ResultType.Error); }
}
}
и есть две реализации:
public class PropertyValidationResultItem : ValidationResultItem
{
public PropertyValidationResultItem(ResultType resultType, string message, string propertyName, object attemptedValue) : base(resultType, message)
{
PropertyName = propertyName;
AttemptedValue = attemptedValue;
}
public string PropertyName { get; private set; }
public object AttemptedValue { get; private set; }
}
и
public abstract class BusinessValidationResultItem : ValidationResultItem
{
protected BusinessValidationResultItem(ResultType resultType, string message) : base(resultType, message)
{
}
}
Каждый обработчик команд имеет собственную реализацию BusinessValidationResultItem, например:
public class AddArticleBusinessValidationResultItem : BusinessValidationResultItem
{
public enum AddArticleValidationResultCode { UserDoesNotExist, UrlTitleAlreadyExists, LanguageDoesNotExist }
public AddArticleBusinessValidationResultItem(ResultType resultType, string message, AddArticleValidationResultCode code)
: base(resultType, message)
{
Code = code;
}
public AddArticleValidationResultCode Code { get; set; }
}
Это означает, что если клиент получает ValidationResult, он может привести BusinessValidationResultItem к конкретному AddArticleBusinessValidationResultItem и, таким образом, использовать конкретное перечисление в операторе switch - избегая волшебных строк.