First, you need to have PostSharp 3 CTP (3.0.5) installed.
To add a contract to to a parameter, just position the caret to the parameter name and select the relevant smart tag:
After you click on the action, PostSharp will download and install the relevant NuGet packages to your project, and add a [Required] custom attribute to the parameter. The same works for fields and properties.
It could not be easier. Of course, you can also introduce contracts without the user interface by installing the package PostSharp.Toolkit.Domain and adding the custom attribute yourself.
public void Foo( [Required] string bar )
(Make sure to allow pre-releases if you install the package manually.)
Ready-Made Contracts
The following contracts are available in the PostSharp.Toolkit.Contracts namespace, depending on the type of the field, property or parameter:
NotNull | Requires a non-null value |
NotEmpty | Requires a non-null and non-empty string or collection |
Required | Requires a non-null object or a non-whitespace string |
CreditCard | Requires a valid credit card number |
EmailAddress | Requires a valid email address |
Phone | Requires a valid phone number |
RegularExpression | Requires a match of a regular expression |
StringLength | Requires a string of a given length |
EnumDataType | Requires a valid value for an enumeration (can be applied to strings and integers) |
GreaterThan | Requires a value greater than a threshold. |
LessThan | Requires a value less than a threshold. |
Positive | Requires a value greater or equal to 0. |
StrictlyPositive | Requires a value strictly greater than 0. |
Range | Requires a value within a range. |
High Performance and Flexibility
Unlike previous validation aspects based on OnMethodBoundaryAspect, the new aspects result in compact and fast code, with almost no overhead compared to hand-written code.
Yet, they are based on an abstraction that you can extend to develop your own contracts: ILocationValidationAspect<T> is a new aspect primitive designed specifically for the task. It works transparently for fields, properties, and parameters.
If you want to create your own contract, you can derive a class from System.Attribute, or preferably PostSharp.Extensibility,MulticastAttribute (which supports inheritance, see below), and ILocationValidationAspect<T>, where T is the type of values to be validated, as many times as necessary. Note that the aspect does not know any standard type conversion (other than down-casting, which is not a conversion), so you will need a lot of these Ts, for instance for int, int?, long, long?, and so on if you want to target numbers.
Contract Inheritance
If you apply a contract to a parameter of an interface, abstract or virtual method, any the contract will be implemented in any derived method, for instance:
interface IFoo { void Bar( [Required] string fooBar ); } class Foo : IFoo { public void Bar( string fooBar ) { // PostSharp will inject the [Required] contract at the top of this method body. } }
Note that inheritance is a feature of MulticastAttribute and not just contracts, so you can use it with just any aspect.
Limitations
I already mentioned that the aspect does not support any type conversion, which could be annoying if you need to develop contracts that work on numbers.
Also note that the aspect is not yet able to validate output argument and return values. It is purely a precondition checker.
Finally, note that all contracts are opt-in. There is no “not-null by default”. It would be fairly easy to develop such a policy using an assembly-level IAspectProvider, but currently you have to do it yourself.
Summary
PostSharp 3 introduces a new aspect primitive that is optimized to validate fields, properties, and parameters with high run-time efficiency. The PostSharp Domain Toolkit contains a set of standard contracts that you can add to your code easily – just using the smart tags in Visual Studio.
Happy PostSharping!
-gael