Skip to content

Add Contract

Michael Damatov edited this page Sep 10, 2025 · 7 revisions

Suggests adding code contracts for commonly used scenarios

Note

Adding code contracts is not suggested anymore when nullable reference types (C# 8.0 or higher) are enabled.

Commonly used contracts

Context action When suggested
Add contract: x ≠ null* x is nullable
Add contract: x.Count > 0 x is ICollection<T>
Add contract: x.All(item => item ≠ null)** x is ICollection<T> and T is nullable
Add contract: x.All(pair => pair.Value ≠ null) x is IDictionary<TKey,TValue> and TValue is nullable
Add contract: !string.IsNullOrEmpty(x)* x is string
Add contract: x = enum.X || x = enum.Y… x is enum
Add contract: x ≥ enum.X && x ≤ enum.Y x is enum and enum is gapless
Add contract: x ≥ flags.None && x ≤ (flags.X | flags.Y…) x is flagged enum and is gapless
Add contract: x > 0 x is number
Add contract: x = 0 x is number
Add contract: x ≥ 0 x is number (signed)
Add contract: x ≠ 0 x is number (signed)
Add contract: x < 0 x is number (signed)
Add contract: x ≤ 0 x is number (signed)
Add contract: x ≠ Guid.Empty x is Guid
Add contract: x.TimeOfDay ≠ TimeSpan.Zero x is DateTime
Add contract: x > TimeSpan.Zero x is TimeSpan
Add contract: x = TimeSpan.Zero x is TimeSpan
Add contract: x ≥ TimeSpan.Zero x is TimeSpan
Add contract: x ≠ TimeSpan.Zero x is TimeSpan
Add contract: x < TimeSpan.Zero x is TimeSpan
Add contract: x ≤ TimeSpan.Zero x is TimeSpan
Add contract: x = (U)IntPtr.Zero x is IntPtr or UIntPtr
Add contract: x ≠ (U)IntPtr.Zero x is IntPtr or UIntPtr

* The [NotNull] annotation is also applied

** The [ItemNotNull] annotation is also applied

Applies to

If suggested on Applied
non-static fields in the object invariant method*
non-auto properties as preconditions for setters and post-conditions for getters
non-static auto properties in the object invariant method*
indexers as preconditions for setters and post-conditions for getters
methods as post-conditions for return values
parameters as preconditions for input and ref parameters and post-conditions for ref and out parameters

* The object invariant method is created if missing.

Abstract and interface members

The contracts are added to the contract class. The contract class and corresponding annotations (both ways) are added if missing.

Current Limitations

Expression-bodied members

  • Expression-bodied methods (incl. the "contact invariant" methods);
  • expression-bodied constructors;
  • expression-bodied operators;
  • expression-bodied properties (and indexers);
  • properties (and indexers) with expression-bodied getters and setters;

are currently not supported.

Workaround: manually convert the member to use the statement body.

Local functions

Local functions are currently not supported.

Creating contract class for generic abstract class or generic interface

Adding a contract to a member of a generic abstract class or a generic interface adds the incorrect [ContractClass(typeof(MyGenericClassContract))] annotation (the correct annotation is [ContractClass(typeof(MyGenericClassContract<,*>))]).

* depends on amount of generic parameters: <> for one generic parameter, <,> for two, <,,> for three, and so on.

Workaround: manually fix the incorrectly generated code.

Clone this wiki locally