Another one of my little snippets of free code that come in handy. This is one is useful for performing ad-hoc operations on sets of objects (i.e. Validations)
This code is now hosted on CodePlex. Please use changeset 14749 to get the latest version of the code. Go get it
/// <summary>
/// Represents a single self evaluating rule.
/// </summary>
/// <remarks>Based on the specification pattern (Evans, Domain Driven Design).</remarks>
/// <typeparam name="T">The type to validate.</typeparam>
public interface IRule<T>
{
/// <summary>
/// Validates the supplied object optionally returning a modified instance.
/// </summary>
/// <param name="item">The object to validate.</param>
/// <returns>The optionally modified instance.</returns>
/// <exception cref="ValidationException">Thrown when an validation exception occurs.</exception>
T Evaluate(T item);
}
/// <summary>
/// Represents a callback method to be executed by the <see cref="DynamicRule{T}"/>.
/// </summary>
/// <param name="item">The object to validate.</param>
/// <returns>The optionally modified instance.</returns>
/// <exception cref="ValidationException">Thrown when an validation exception occurs.</exception>
public delegate T EvaluateCallback<T>(T item);
/// <summary>
/// Represents a dynamic rule that executes a <see cref="EvaluateCallback{T}"/> delegate.
/// </summary>
/// <typeparam name="T">The type to validate.</typeparam>
public sealed class DynamicRule<T> : IRule<T>
{
private readonly EvaluateCallback<T> callback;
/// <summary>
/// Initializes a new instance of the <see cref="DynamicRule{T}"/> class with the supplied callback.
/// </summary>
/// <param name="callback">The callback to evaluate.</param>
public DynamicRule(EvaluateCallback<T> callback)
{
this.callback = callback;
}
/// <summary>
/// Validates the supplied object optionally returning a modified instance.
/// </summary>
/// <param name="item">The object to validate.</param>
/// <returns>The optionally modified instance.</returns>
/// <exception cref="ValidationException">Thrown when an validation exception occurs.</exception>
public T Evaluate(T item)
{
return this.callback(item);
}
}
</code></pre>
To add to the usefulness I've taken a special implementation of IRule<T> for performing validations.<br /><br />
<pre><code>
/// <summary>
/// Simple validator harness for performing checks on any instance of a type.
/// </summary>
/// <typeparam name="T">The type to validate.</typeparam>
public class Validator<T> : IRule<T>
{
private readonly IEnumerable<IRule<T>> rules;
/// <summary>
/// Initializes a new instance of the <see cref="Validator{T}"/> type with the supplied <see cref="IRule{T}">rules</see>.
/// </summary>
/// <param name="rules">A parameter array of <see cref="IRule{T}">rules</see> for the validator to operate with.</param>
public Validator(params IRule<T>[] rules) : this((IEnumerable<IRule<T>>)rules) { }
/// <summary>
/// Initializes a new instance of the <see cref="Validator{T}"/> type with the supplied <see cref="IRule{T}">rules</see>.
/// </summary>
/// <param name="rules">The arrays of <see cref="IRule{T}">rules</see> for the validator to operate with.</param>
public Validator(IEnumerable<IRule<T>> rules)
{
this.rules = rules ?? new IRule<T>[] { };
}
/// <summary>
/// Validates the supplied object optionally returning a modified instance.
/// </summary>
/// <param name="item">The object to validate.</param>
/// <returns>The optionally modified instance.</returns>
/// <exception cref="ValidationException">Thrown when an validation exception occurs.</exception>
public T Evaluate(T item)
{
try
{
foreach (IRule<T> rule in this.rules)
{
if (rule == null) continue;
item = rule.Evaluate(item);
}
return item;
}
catch (Exception ex)
{
throw new ValidationException(ex.Message, ex);
}
}
}
/// <summary>
/// Exception for representing validation issues.
/// </summary>
[Serializable()]
public class ValidationException : Exception
{
/// <summary>
/// Initializes a new instance of the <see cref="ValidationException"/> class.
/// </summary>
public ValidationException() { }
/// <summary>
/// Initializes a new instance of the <see cref="ValidationException"/> class with a specified error message and a reference to the inner exception that is the cause of this exception.
/// </summary>
/// <param name="message">The message that describes the error.</param>
/// <param name="innerException">The exception that is the cause of the current exception, or <see langkeyword="null">null</see> if no inner exception is specified.</param>
public ValidationException(String message, Exception innerException) : base(message, innerException) { }
/// <summary>
/// Initializes a new instance of the <see cref="ValidationException"/> class with a specified error message
/// </summary>
/// <param name="message">The message that describes the error.</param>
public ValidationException(String message) : base(message) { }
}
Enjoy... |