Reputation: 7438
I have a class Employee. I want to be able to Validate() it before I save it to make sure all the fields have been populated with valid values. The user of the class may call Validate() before they call Save() or they may call Save() directly and Save() will then call Validate() and probably throw an Exception if validation fails.
Now, my (main) question is this;
If my Validate() function returns a simple bool then how do I tell the user of the class what is wrong, i.e. "Email not filled in", "ID not unique" etc. For the purposes of this I just want the error strings to pass to the human user, but the principle is the same if I wanted a list of error codes (except that makes the use of a bitmap more logical).
My specific program is in C# but this looks like a fairly generic "best practice" question and one I am sure I should know the answer to. Any advice gratefully received.
Upvotes: 8
Views: 2949
Reputation: 6845
I agree with Chris W. I asked the same questions, before reading Rocky`s Expert C# Business Objects.
He has a brilliant way of handling business validation rules. The validation is done after each property is set. Whenever a rule is broken, the object`s state become InValid.
Your business class can implement the IDataError interface. Binding your UI controls to your business object properties will then notify your ErrorProvider control of any broken rules on your object.
I would really recommend you take the time and look at the validation section.
Upvotes: 1
Reputation: 3314
You could take a look at Rockford Lhotka's CSLA which has extensive business rule/validation tracking forr business objects in it.
www.lhotka.net
Upvotes: 1
Reputation: 14485
Sounds like you need a generic class:
public sealed class ValidationResult<T>
{
private readonly bool _valid; // could do an enum {Invalid, Warning, Valid}
private readonly T _result;
private readonly List<ValidationMessage> _messages;
public ValidationResult(T result) { _valid = true; _result = result; _messages = /* empty list */; }
public static ValidationResult<T> Error(IEnumerable<ValidationMessage> messages)
{
_valid = false;
_result = default(T);
_messages = messages.ToList();
}
public bool IsValid { get { return _valid; } }
public T Result { get { if(!_valid) throw new InvalidOperationException(); return _result; } }
public IEnumerable<ValidationMessage> Messages { get { return _messages; } } // or ReadOnlyCollection<ValidationMessage> might be better return type
// desirable things: implicit conversion from T
// an overload for the Error factory method that takes params ValidationMessage[]
// whatever other goodies you want
// DataContract, Serializable attributes to make this go over the wire
}
Upvotes: 1
Reputation: 43243
I have found it a good approach to simply have a method (or a property, since C# has nice support for that) which returns all validation error messages in some kind of sensible, easy to use format, such as a list of strings.
This way you can also keep your validate method returning bools.
Upvotes: 1
Reputation: 11890
We are using spring validation together with an Windows Forms error provider.
So our validation function returns a dictionary with a control id and an error message (for every validation error). The error provider shows the error message in a pop up field near the control which caused the error.
I used some other validation schemes in the past - but this one works really well.
Upvotes: 0
Reputation: 397
I would probably go for the bitmap-option. Simply
[Flags]
public enum ValidationError {
None = 0,
SomeError = 1,
OtherError = 2,
ThirdError = 4
}
...and in the calling code, simply:
ValidationError errCode = employee.Validate();
if(errCode != ValidationError.None) {
// Do something
}
Seems nice and compact to me.
Upvotes: 5
Reputation: 49261
I would follow the pattern of the TryParse methods and use a method with this signature:
public bool TryValidate(out IEnumerable<string> errors) { ... }
Another option is to pull the validation code out of the object into its own class, possibly building on the Specification pattern.
public class EmployeeValidator
{
public bool IsSatisfiedBy(Employee candidate)
{
//validate and populate Errors
}
public IEnumerable<string> Errors { get; private set; }
}
Upvotes: 1
Reputation: 545608
I could create a Struct just to return from this method, including a bool and a string array with error messages, but just seems clunky.
Why does it seem clunky? Creating an appropriate type to encapsulate the information is perfect. I wouldn't necessarily use a string to encode such information, though. An enum may be better suited.
An alternative would be to subclass the return type and provide an extra child class for every case – if this is appropriate. If more than one failures may be signalled, an array is fine. But I would encapsulate this in an own type as well.
The general pattern could look like this:
class ValidationInfo {
public bool Valid { get; private set; }
public IEnumerable<Failure> Failures { get; private set; }
}
Upvotes: 6