Walkthrough: Adding Contracts to Code

This section describes how to add a contract to a field, property, or parameter.

This topic contains the following sections:

Introduction

Consider the following method which checks if a valid string has been passed in:

C#
public class CustomerModel
{
  public void SetFullName(string firstName, string lastName)
  {
      if(firstName == null)
        throw NullReferenceException();

      if(lastName == null)
        throw NullReferenceException();

      this.FullName = firstName + " " + lastName;
  }
}

In this example, checks have been added to ensure that both parameters contain a valid string. A better solution is to place the logic which performs this check into its own reusable class, especially such boilerplate logic is involved, and then reuse/invoke this class whenever the check needs to be performed.

PostSharp’s Contract attributes do just that by moving such checks out of code and into parameter attributes. For example, PostSharp’s RequiredAttribute contract could be used to simplify the example as follows:

C#
public class CustomerModel
{
    public void SetFullName([Required] string firstName, [Required] string lastName)
    {
        this.FullName = firstName + " " + lastName;
    }
}

In this example the RequiredAttribute attribute performs the check for null, thus eliminating the need to write the boiler plate code for the check inline with other code.

A contract can also be used in a property as shown in the following example:

C#
public class CustomerModel
 {
    [Required]
    public FirstName
    {
        get;
        set;
    }
}

Using a contract in a property ensures that the value being passed into set is validated before the logic (if any) for set is executed.

Similarly, a contract can be used directly on a field which will validate the value being assigned to the field:

C#
public class CustomerModel
{
    [Required]
    private string mFirstName = “Not filled in yet”;

    public void SetFirstName(string firstName)
    {
        mFirstName = firstName;
    }
}

In this example, firstName will be validated by the Required contract before being assigned to mFirstName. Placing a contract on a field provides the added benefit of validating the field regardless of where it’s set from.

Note that PostSharp also includes a number of built-in contracts which range from checks for null values to testing for valid phone numbers. You can also develop your own contracts with custom logic for your own types as described below.

There are two ways to add contracts:

Adding contracts using PostSharp Tools for Visual Studio

PostSharp’s Visual Studio integration provides a smart tag popup which can be used to select and apply a contract to a parameter, field, or property.

To add contract using PostSharp Tools for Visual Studio:

  1. Click on the parameter, field, or property for which the contract is to be applied. While hovering the mouse over this item, a smart tag drop-down will appear:

    Adding Contracts 1
  2. Click on the smart tag drop-down to reveal the contracts available:

    Adding Contracts 2
  3. Select a contract from the list or select Add another aspect to display the aspect selection dialog:

    Adding Contracts 3
  4. Select a contract and click Next.

  5. Confirm the addition of the contract and click Next:

    Adding Contracts 4
  6. Click Finish when the dialog indicates that the operation completed:

    Adding Contracts 5

The aspect has now been added in code:

Adding Contracts 6
Adding contracts manually

To add contract manually:

  1. Add the PostSharp.Patterns.Model assembly to your project.

  2. Add the namespace containing the code contacts you plan to use.

    You can find a full list of available ready-made patterns in the documentation of the PostSharp.Patterns.Contracts namespace.

  3. Add the attribute before the parameter name. For example:

    C#
    public void SetFullName([Required] string firstName, [Required] string lastName)
Contract Inheritance

PostSharp ensures that any contracts which have been applied to an abstract, virtual, or interface method are inherited along with that method in derived classes, all without the need to re-specify the contract in the derived methods. This is shown in the following example:

C#
public interface ICustomerModel
{
  void SetFullName([Required] string firstName, [Required] string lastName);
}

public class CustomerModel : ICustomerModel
{
  public void SetFullName(string firstName, string lastName)
  {
     this.FullName = firstName + " " + lastName;
  }

}

Here ICustomerModel.SetFullName method specifies that the firstName and lastName parameters are required using the RequiredAttribute attribute. Since the CustomerModel.SetFullName method implements this method, these attributes will also be applied to its parameters.

Note Note

If the derived class exists in a separate assembly, that assembly must be processed by PostSharp and must reference PostSharp and PostSharp Model pattern assembly.