Getting Started with Rx Code Contracts
What are Code Contracts?
is a set of tools from Microsoft that integrates seamlessly into Visual Studio and enables developers to write contracts in their code, such as (but not limited to):
- Preconditions: Argument validation and requirements about object state.
- Post-conditions: Ensurances about return values and object state.
- Invariants: Global ensurances about the internal state of an object.
Contracts are checked at runtime and/or compile time to ensure the proper use of a decorated API. Contracts are also inherited automatically when you derive from an API that has inheritable contracts.
Unfortunately, Rx is not built with Code Contracts
. It can be cumbersome to use Rx with Code Contracts enabled due to all of the contract warnings. The typical way to silence the warnings is to make a lot of explicit assumptions using Contract.Assume
, but this is counterproductive. Furthermore, preconditions in Rx are written in the classic if..then..throw style, which doesn't provide Code Contracts with the information that it needs to warn you when you're misusing an API.
What are Rx Code Contracts?
Rx Code Contracts are unofficial Code Contracts reference assemblies that contain the public contracts for Rx. These contract reference assemblies work with the Code Contracts static checker tool to validate your usage of the Rx library at compile time. They are also used by the Code Contracts rewriter tool to inherit contracts at compile time.
Note: Rx Code Contracts have absolutely no effect on the runtime behavior of Rx. Therefore, if you notice any inconsistencies between the public contracts defined in Rx Code Contracts and the actual runtime behavior of Rx, then please report issues to us so that we may fix the contracts to match the actual runtime behavior.
Rx Code Contracts enables the Code Contracts static checker to check things like:
- You are not passing in a negative number for the count argument of Observable.Range.
- You are not passing in a negative TimeSpan value to Observable.Window.
- You are not passing in null (Nothing in Visual Basic) to Observable.Concat.
And to ensure things like:
- The return value of Observable.Select will never be null (Nothing in Visual Basic).
- The Notification<T>.Value property will not throw an exception if the Notification<T>.HasValue property is equal to true (True in Visual Basic).
- When implementing IObservable<T>.Subscribe, the observer parameter will never be null (Nothing in Visual Basic).
- Do not add references to the Rx Code Contracts assemblies; doing so will cause build errors in your projects. These assemblies are not intended to be used from code, they are only intended to be used by the Code Contracts tools.
- Do not deploy Rx Code Contracts assemblies with your application. These assemblies are only useful at compile-time.
Rx Code Contracts assemblies are available for the following platforms.
Note: Each assembly supports both Rx Stable and Rx Experimental for its target platform.
- .NET 4.0
- Silverlight 4
- Silverlight 5
- Windows Phone 7.0
- Windows Phone 7.1
Rx Code Contracts has the following dependencies.
How to Install Rx Code Contracts
The Code Contracts tools must be able to locate the Rx Code Contracts assemblies at compile-time. There are two ways to accomplish this:
- Place the Rx Code Contracts assemblies in the same directory as the Rx assemblies that your project references.
- Place the Rx Code Contracts assemblies in a separate directory and then add the directory to the Code Contract's Extra Contract Library Paths configuration property.
If you have downloaded Rx from NuGet, then the second option is preferable so that you don't have to modify NuGet's packages
folder. See the instructions below for details.
How to Install Rx Code Contracts in a Separate Directory (Option #2):
- Copy the Rx Code Contracts assemblies into a new directory, such as an External References folder at the root of your solution.
- If you need to support multiple platforms, then place each contract assembly into its own subdirectory and use an appropriate name; e.g., Net4, SL4 or WP7.
- Open your project properties.
- Select the Code Contracts tab.
- Under the Advanced section, locate the Extra Contract Library Paths textbox and enter the full path to the directory that contains the Rx Code Contracts assemblies; e.g., C:\Projects\MyApp\External References\Rx Code Contracts\Net4
- A full path must be specified. Relative paths are not recommended because Code Contracts doesn't consistently use the same root directory, which is not the project directory. See below for a workaround.
- Do not add a trailing slash.
- Do not surround the path in quotes, even if it contains spaces.
- Separate multiple directories with semicolons (;).
- Save your changes.
As mentioned above, you must enter full paths in the Extra Contract Library Paths
setting. However, this can present problems when working on a team because some developers will use different base paths for the project. To specify a relative path instead, follow this procedure:
- Make sure that the Extra Contract Library Paths setting is blank.
- Save the project.
- Open the project file so that it can be edited.
- Right-mouse click the project node in Solution Explorer and select Unload Project. The project is unloaded and the project node is grayed out.
- Right-mouse click the grayed out project node in Solution Explorer and select Edit [your project].
- Locate the project's primary <Import> element. For example, a C# class library project will have <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />.
- After the primary <Import> element, add the following <PropertyGroup>:
<AddCC>$(MSBuildProjectDirectory)\External References\Rx Code Contracts\Net4</AddCC>
- Replace the path in the example (External References\Rx Code Contracts\Net4) with the appropriate path to the Rx Code Contracts assemblies, relative to your project.
- Save your changes.
- Right-mouse click the grayed out project node in Solution Explorer and select Reload Project.
Note: When you open the Code Contracts tab in your project properties now, you may see a full path in Extra Contract Library Paths. This is a result of the dynamic project system in Visual Studio evaluating the property that you've just added. However, each team member should see the path that is appropriate for their system. Do not modify this setting here.