ValueOf
ValueOf copied to clipboard
Validate without exceptions?
I'm new to ValueObjects so forgive me if this is a bad idea, but I wanted to avoid throwing exceptions during validation for a variety of reasons and instead have a collection of validation errors. So I added:
private readonly List<TValidationResult> _errors;
and later:
public List<TValidationResult> Errors => _errors ?? new();
public IReadOnlyList<TValidationResult> ValidationErrors => _errors.AsReadOnly();
To the ValueOf base class. This allows the ValueOf consumer to decide whether Validate should throw exceptions, or TryValidate should just fail silently; or whether both should append one or more validation errors to a collection that can be displayed to a user or logged.
Is there a reason I'm unaware of as to why throwing exceptions seems to be the preferred validation mechanism?
This allows the ValueOf consumer to decide whether Validate should throw exceptions, or TryValidate should just fail silently; or whether both should append one or more validation errors to a collection that can be displayed to a user or logged.
The consumer can still perform all of the validations on it's own, without having to call the Validate
or TryValidate
methods. Would it makes sense to "outsource" your validation logic to a separate class or a separate, re-usable method? In the code below, the CheckValidation
method is public static - anyone can call it and see what errors, if any, would cause Validate
to throw or TryValidate
to fail. And depending on your needs, you can exit early from CheckValidation
to stop accruing redundant errors.
public class EmailAddress : ValueOf<string, EmailAddress>
{
protected override void Validate()
{
var errors = CheckValidation(Value);
if (errors.Count > 0)
{
// Throw an exception that corresponds to your error
}
}
protected override bool TryValidate()
{
return CheckValidation(Value).Count == 0;
}
public static List<StringPrimitiveValidationFailure> CheckValidation(string value)
{
var errors = new List<StringPrimitiveValidationFailure>();
if (value is null)
{
errors.Add(StringPrimitiveValidationFailure.IsNull);
}
if (string.IsNullOrWhiteSpace(value))
{
errors.Add(StringPrimitiveValidationFailure.IsEmpty);
}
if (value.Trim().EndsWith('.'))
{
errors.Add(StringPrimitiveValidationFailure.Invalid);
}
try
{
var addr = new System.Net.Mail.MailAddress(value);
}
catch
{
errors.Add(StringPrimitiveValidationFailure.Invalid);
}
return errors;
}
}