home | downloads | recipes | blogs | staff | about us | *

The Art of Lightning
Even more free codeJames Zimmerman10/24/2007

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... 

Look for more blogs |

(c) 2001-2012 Stuart Williams, E-Mail Stuart Williams