A Flexible Guard Class

Writing a guard class that implements parameter checks seems to be simple – but can become complex if you want some additional features (e.g. logging for rule violation, custom rules etc.). Also code contracts may be too much to learn/invest for your team/project.
The guard class presented in this sample project can easily be implemented, supports central and per project definition of validation rules, enables you to add aspects like logging and implements debug-only checks to perform more restrictive checks while running a debug build.
I’ll start with the sample project, which is quiet simply:

namespace GuardSample
{
  using System;
  using Sem.GenericHelpers.Contracts;

  class Program
  {
    static void Main(string[] args)
    {
      ParameterTest1(componentOne, 7);
      Console.ReadLine();
    }

    public static void ParameterTest1(SampleClass message,
                                      int number)
    {
      Guard.For(() => message)
        .Assert(RuleSets.SampleRuleSet<SampleClass>())
        .Assert(x => x.LastMsg != "{magic}");

      Guard.For(() => number)
        .Assume(Rules.BackEndNumberBoundaries())
        .Assert(Rules.IsNotOneOf<int>(), new[] { 1, 3, 5, 7 });

      Console.WriteLine();
      Console.WriteLine(@"message         : " + message);
      Console.WriteLine(@"message.LastMsg : " + message.LastMsg);
      Console.WriteLine(@"number          : " + number);
    }
  }
}

As you can see we are calling a method performing an action (writing to the console) based on the value of a parameter – so the parameter must be checked for validity.In this sample we check the parameter with two asserts per parameter. The first assert for the parameter “message” checks for a rule set (a list of predefined rules), the second for a “custom logic”. The checks of the second parameter are very similar.
The For method of the Guard class simply initializes a generic data-checking class CheckData<TData>, which hosts the Assert methods. The parameter is the data to be checked, but it’s specified as a Lambda expression, so the For method can get the parameter name without specifying it as a string:

public static CheckData<TData> For<TData>(Expression<Func<TData>> data)
{
    var member = data.Body as MemberExpression;
    var name = member != null
                ? member.Member.Name
                : "anonymous value";

    return For(data.Compile().Invoke(), name);
}

public static CheckData<TData> For<TData>(TData data, string name)
{
    return new CheckData<TData>
        {
            ValueName = name,
            Value = data
        };
}

The property Value of that class is of type TData, so that we can access it strongly typed. One overload of the Assert method of that class does accept a rule:

public CheckData<TData> Assume(Rule<TData> rule)
{
    rule.AssumeFor(this);
    return this;
}

By returning the this instance, we can implement a fluid interface, so we can check multiple rules in one line for the same parameter.The rule inherits from the abstract class RuleBase<TExpression>:

public abstract class RuleBase<TExpression>
{
    public string Message { get; set; }
    public Func<string, string, Exception> ThrowException { get; set; }
    public TExpression CheckExpression { get; set; }

    protected RuleBase()
    {
        this.Message = "There is a problem with the parameter.";
        this.ThrowException = (message, parameterName)
            => new ArgumentException(this.Message, parameterName);
    }

    protected void InvokeInternal(Func<bool> toCheck,
                                  string parameterName)
    {
        if (!toCheck())
        {
            var exception = this.ThrowException(this.Message,
                                                parameterName);
            throw exception;
        }
    }
}

As shown here, the base class implements all functionality the Rule class only implements the function call that depends on the count of check-parameters:

public class Rule<TValue> :
             RuleBase<Func<TValue, bool>>
{
    public void AssertFor(CheckData<TValue> value)
    {
        this.InvokeInternal(
            () => this.CheckExpression(value.Value),
            value.ValueName);
    }
}

This way we encapsulate the statement that evaluates the CheckExpression method which is Func<TValue, bool> as defined in the generic parameter of the RuleBase inheritance. We need different inherited classes in order to support rules that do accept different counts of parameters.The implementation of InvokeInternal does accept a function that returns a Boolean instead of accepting the Boolean directly. This enables us to execute logging before executing the check expression, implement a generic exception handler for executing all rule checks etc.
A second rule class has been implemented using a different check function signature:

public class Rule<TValue, TCheckParameter> :
             RuleBase<Func<TValue, TCheckParameter, bool>>
{
  public void AssertFor(CheckData<TValue> value,
                        TCheckParameter checkParameter)
  {
    this.InvokeInternal(
          () => this.CheckExpression(value.Value, checkParameter),
          value.ValueName);
  }
}

As you can see, the only difference is the count of parameters for the check expression, which is of type Func< TValue, TCheckParameter, bool > – until now we didn’t implement any check logic. The Rules class does define the predefined check logic. Here is one example:

public static Rule<int> BackEndNumberBoundaries()
{
    return new Rule<int>
    {
        CheckExpression = parameterValue => parameterValue < 16000
                          && parameterValue > -16000,
        Message = "Provided value is not of the expected values",
        ThrowException = (message, parameterName)
                         => new ArgumentOutOfRangeException(
                           parameterName,
                           "the backend currently only supports " +
                           "values between -16000 and 16000"),
    };
}

So each “predefined” rule is a (sometimes generic) static method that returns a class instance that inherits from RuleBase and implements AssertFor (which is called by the Assert method of CheckData). Unfortunately there are no “generic properties”, so we cannot use that – which would have allowed us persisting the rules into XML and load them from a file.
To enable in place definition of check expressions, I’ve added an overload of the Assert method accepting a Func<TData, bool>:

public CheckData<TData> Assert(Func<TData, bool> rule)
{
    var ruleClass = new Rule<TData> { CheckExpression = rule };
    return Assert(ruleClass);
}

public CheckData<TData> Assert(Rule<TData> rule)
{
    rule.AssertFor(this);
    return this;
}

In the sample project, there are more overloads, so you can omit the message, use different rule types (with different parameters) etc. – including an overload that accepts IEnumerable<Rule<TData>>, so that you can define rule sets that can be managed in a central way (e,g, if you want to check all incoming strings on the service boundary for something special).
Another little assert I’ve added is being called like this:

Guard.For(() => myMessageOne).Assert();

Whoups – where’s the rule? The magic in this case is done by registering the rules for a specific type elsewhere, so that each time an Assert is called without specifying a rule, the default rules of the type (MessageOne in this case) are applied. The Assert statement is like this:

public CheckData<TData> Assert()
{
    var ruleSet = RuleSets.GetRulesForType(typeof(TData));
    foreach (var typeRule in ruleSet)
    {
        this.Assert((Rule<TData>)typeRule.Rule);
    }

    return this;
}

The rule is not provided directly, but by looking up type matching rules in a list of registered rules:private static readonly List<TypeRule> _RegisteredRules = new List<TypeRule>();

public static void RegisterRule<TValue>(Rule<TValue> rule)
{
    _RegisteredRules.Add(
           new TypeRule
                {
                    ValueType = typeof(TValue),
                    Rule = rule
                });
}

internal static IEnumerable<TypeRule> GetRulesForType(Type type)
{
    return
        from x in _RegisteredRules
        where x.ValueType == type select x;
}

This enables us to specify a list of rules as the default specification of a data type (business entity).
Hope this guard class example will help you with some problems it will solve.
For a great introduction into guard classes also have a look at Posting Guards: Guard Classes explained (AJ’s blog)
I’ll integrate the complete source code with 100% covering unit tests and a little sample method to my project at CodePlex: Sem.Sync – and I promise to do it in a way that you will be able to use it without using the rest of the project 😉 . A draft version can be downloaded from here.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Sylvio's Infobox

Aktuelle Themen rund um SQL Server, BI, Windows, ...

Meredith Lewis

Professional Digital Portfolio

Vittorio Bertocci

Just another WordPress.com weblog

ScottGu's Blog

Just another WordPress.com weblog

AJ's blog

Thoughts and informations I think worthwhile to share...

Outlawtrail - .NET Development

Architecture & Design

SDX eXperts Flurfunk

Just another WordPress.com weblog

%d bloggers like this: