Better C# Design Contracts in Lokad Shared Libraries
Extensive codebase is one of the best testers.
I've just finished updating Enforce statements from the Lokad Shared Libraries with the new syntax that is based on retrieval of parameter name from .NET lambda with IL parsing. A couple of usability and stability issues were discovered and fixed wile pushing changes to the existing code-bases leveraging Lokad Shared.
And so there is the updated new syntax for declaring design contracts for arguments. Basically we just replace variable with the lambda and drop the duplicate name entry:
// null or empty check for strings
Enforce.ArgumentNotEmpty(companyName, "companyName");
// new syntax
Enforce.ArgumentNotEmpty(() => companyName);
// null check and rule check
Enforce.Argument(newName, "newName", ChecksFor.NewName);
// new syntax
Enforce.Argument(() => newName, ChecksFor.NewName);
// null checks for the collection and rule check for items
Enforce.Argument(messages, "messages", RulesFor.Message);
// new syntax
Enforce.Argument(() => messages, RulesFor.Message);
Additionally, There's a nice improvement in lowering code duplication. This code block:
Enforce.Argument(controller, "controller");
Enforce.Argument(viewManager, "viewManager");
Enforce.Argument(workspace, "workSpace");
can be replaced by a single line:
Enforce.Arguments(() => controller, () => viewManager,() => workspace);
Obviously, variable name and its type will be retrieved and included into the exception, should any of the checks fail.
New package of Lokad Shared Libraries has been released (direct link).
Monday, December 22, 2008 at 14:16
Reader Comments (8)
Would it be possible to get some usage examples on the Enforce.That and Enforce.With variants as well?
And how to create and use the Rule<T> delegate with these methods?
Svish,
More information on rules could be found in article on this application block.
For real-world usage examples of using Enforce variants, you may check out this open-source project that is one of the primary consumers of the Lokad Shared Libraries.
By the way, a class from this project - Lokad.Api.Core.ApiRules contains quite a large set of rules that could serve as a sample.
Does this help you?
Tried to look at it, but can't say that it made anything much clearer. Probably just me that is slow here :p
Maybe you could help me? What I would like is to Enforce that an IEnumerable<T> parameter is not null, is not empty, and does not contain any null items. And have a sensible exception when this was not the case. How would I do that?
Here's the simplest implementation with the usages:
public static class EnumerableIs
{
public static void NotEmpty<T>(IEnumerable<T> collection, IScope scope)
{
if (!collection.Any())
{
scope.Error("Enumerable can't be empty");
}
scope.ValidateInScope(collection);
}
}
[Test, ExpectedException(typeof(ArgumentException))]
public void Test()
{
IEnumerable<object> t = null;
Enforce.Argument(() => t, EnumerableIs.NotEmpty);
}
[Test, ExpectedException(typeof(ArgumentException))]
public void Test2()
{
var t = new int[0];
Enforce.Argument(() => t, EnumerableIs.NotEmpty);
}
[Test, ExpectedException(typeof(ArgumentException))]
public void Test3()
{
var t= new[] {new object(), null};
Enforce.Argument(() => t, EnumerableIs.NotEmpty);
}
That seemed to work like it should. Although I don't quite understand how :p I got these messages from your 3 tests:
Test1:
Object of type 'IEnumerable`1' should not be null.
Parameter name: t
Test2:
Enumerable can't be empty
Parameter name: t
Test3:
Object of type 'Object' should not be null.
Parameter name: t.[1]
Where does the "Object of type 'IEnumerable`1' should not be null." and "Object of type 'Object' should not be null." come from? Does it have something to do with the scope.ValidateInScope(collection); line? What does that ValidateInScope method do? Tried to look in the Object Browser in VS and see if the xml doc said something about it, but I could only see the method signature of that method.
The primary logic of this validation framework is that it does not allow nulls anywhere it checks.
That's the "good citizenship policy" being enforced.
ValidateInScope is just a short-cut method used internally to run a validation without creating a new scope for it. It passes execution to CheckObject method that ensures object is not null and then runs the rules against it.
You can either download the source code to see for yourself or view it at:
http://code.google.com/p/lokad-shared-libraries/source/browse/trunk/Source/Lokad.Shared/Rules/IScopeExtensions.cs
Thanks for the comprehensive information here. Sometimes it's very hard to find useful information over the internet. Thanks again and waiting for more:))