Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Validate without exceptions? #29

Open
Bitfiddler opened this issue May 10, 2022 · 1 comment
Open

Validate without exceptions? #29

Bitfiddler opened this issue May 10, 2022 · 1 comment

Comments

@Bitfiddler
Copy link

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?

@Jack-Edwards
Copy link
Contributor

Jack-Edwards commented May 18, 2022

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;
   }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants