I think it's much more useful to think of validation as something that's bound to a context - typically an action that you want to do. ContextualValidation di Martin Fowler.
Parole sante, legare la validazione al contesto è un concetto che sto appoggiando da un pò (per le stesse consiederazioni fatte da martin Fowler), abbandonando la validazione _generica_ degli oggetti e indipendetemente dal contesto. Tale modalità di operarare è quella che su cui si basa la validazione per attributi come suggerito in un vecchio (anno 2003) ma brillante tip di Pierre: "Creare un Attributo per implementare Constraint".
Ultimanete sto quindi implementato sistemi di validazione non più basati sull'uso di attributi ma più simili alle validazioni classiche. Uso inoltre un sistema ispirato al "Notification", sempre di Martin Fowler, in modo che ogni procedura che necessità di validazione richiede un oggetto Notification. Al termine della procedura l'oggetto conterrà il risultato (bool success) e una collezione di eventuali errori di validazione.
...la produttività è importante per cui credo sia bene evitare le classifiche carrellate di "If" preferendo invece una serie di Validator generici invocati a catena e configuarti ad hoc per il contesto...
public void ValidateProductForSaving(Product product, Notification notification)
{
//Il nome non può essere nullo e deve avere una lunghezza tra 1 e 50 caratteri.
StringValidator vName = new StringValidator("NAME_NOT_VALID", false, 1, 50);
vName.Validate(product.Name, notification);
//La descrizione piò essere nulla e nel caso non può eccedere i 4000 caratteri.
StringValidator vDescription = new StringValidator("DESCRIPTION_NOT_VALID", true, 4000);
vDescription.Validate(product.Description, notification);
// ...
}
Nel codice dello snippet durante il processo di validazione (for saving) ogni validator aggiunge il/i proprio/propri ValidationError nella collezione di errori del Notification.