Table of Contents

Class SemVer

Namespace
Invex.SemanticVersion
Assembly
Invex.SemanticVersion.dll

An immutable semantic version following the Semantic Versioning 2.0.0 specification. Supports parsing, comparison, and conversion operations for version strings in the format MAJOR.MINOR.PATCH[-PRERELEASE][+METADATA].

[PublicAPI]
public sealed class SemVer
Inheritance
object
SemVer

Examples

var version1 = SemVer.Parse("1.2.3-alpha.1+build.123");
SemVer version2 = "2.0.0";
bool isNewer = version2 > version1; // true

Remarks

This class implements semantic version comparison where:

  • Release versions (without pre-release) are greater than pre-release versions
  • Pre-release versions are compared lexicographically by dot-separated identifiers
  • Numeric identifiers in pre-release are compared numerically (of any length) and have lower precedence than alphanumeric identifiers
  • Metadata is used only as a final tiebreaker when all other components are equal

Create instances with Parse(string), TryParse(string?, out SemVer), FromSystemVersion(Version, bool) or the implicit conversion from string. The public parameterless constructor is obsolete: it always creates version 0.0.0 and cannot set components.

The type implements System.ISpanParsable<TSelf>, System.IComparable<T> and System.Numerics.IComparisonOperators<TSelf, TOther, TResult>, so it works with generic parsing, sorting and ordered collections.

System.Text.Json serializes a SemVer as an object with the Major, Minor, Patch, PreRelease and Metadata properties (null components are written as null) and deserializes it through a private constructor, without a custom converter. The computed properties Prefix, IsPreRelease, BuildNumberFromPreRelease and BuildNumberFromMetadata are not serialized.

Constructors

SemVer()

Initializes a new instance of the SemVer class representing version 0.0.0.

[Obsolete("Use SemVer.Parse, SemVer.TryParse, SemVer.FromSystemVersion or SemVer.One instead. This constructor always creates version 0.0.0 and will be removed in a future major version.")]
public SemVer()

Remarks

This constructor was exposed unintentionally. All properties have private init accessors, so it cannot be used to set components; it always creates version 0.0.0.

Properties

BuildNumberFromMetadata

Gets the build number extracted from the metadata.

[JsonIgnore]
public int BuildNumberFromMetadata { get; }

Property Value

int

The numeric build number if exactly one number is found in the metadata; otherwise, 0 (including when Metadata is null).

Examples

SemVer.Parse("1.0.0+build.99").BuildNumberFromMetadata; // 99
SemVer.Parse("1.0.0+build").BuildNumberFromMetadata;    // 0 (no number)
SemVer.Parse("1.0.0").BuildNumberFromMetadata;          // 0 (no metadata)

Remarks

This property applies the same rules as ExtractBuildNumber(string?) to the metadata string. Only returns a non-zero value if exactly one numeric sequence is present. Unlike ExtractBuildNumber(string?), it never throws: a single numeric sequence greater than int.MaxValue (for example a timestamp such as +20261014123045) also returns 0.

BuildNumberFromPreRelease

Gets the build number extracted from the pre-release identifier.

[JsonIgnore]
public int BuildNumberFromPreRelease { get; }

Property Value

int

The numeric build number if exactly one number is found in the pre-release; otherwise, 0 (including when PreRelease is null).

Examples

SemVer.Parse("1.0.0-rc.42").BuildNumberFromPreRelease; // 42
SemVer.Parse("1.0.0-alpha").BuildNumberFromPreRelease; // 0 (no number)
SemVer.Parse("1.0.0-1.2").BuildNumberFromPreRelease;   // 0 (multiple numbers)
SemVer.Parse("1.0.0").BuildNumberFromPreRelease;       // 0 (no pre-release)

Remarks

This property applies the same rules as ExtractBuildNumber(string?) to the pre-release string. Only returns a non-zero value if exactly one numeric sequence is present. Unlike ExtractBuildNumber(string?), it never throws: a single numeric sequence greater than int.MaxValue also returns 0.

IsPreRelease

Gets a value indicating whether this version is a pre-release version.

[JsonIgnore]
public bool IsPreRelease { get; }

Property Value

bool

true if PreRelease is not null; otherwise, false.

Major

Gets the major version number.

public int Major { get; }

Property Value

int

The major version number, indicating incompatible API changes.

Metadata

Gets the build metadata.

public string? Metadata { get; }

Property Value

string

The build metadata string without the leading plus sign, or null if no metadata is present.

Remarks

The specification ignores metadata when determining version precedence. This implementation uses it as a final tiebreaker (ordinal string comparison) in CompareTo(SemVer?) when all other components are equal, so versions that differ only in metadata are not equal.

Minor

Gets the minor version number.

public int Minor { get; }

Property Value

int

The minor version number, indicating backwards-compatible functionality additions.

One

Gets a semantic version representing version 1.0.0.

public static SemVer One { get; }

Property Value

SemVer

A SemVer instance with Major set to 1, Minor and Patch set to 0, and no pre-release or metadata.

Patch

Gets the patch version number.

public int Patch { get; }

Property Value

int

The patch version number, indicating backwards-compatible bug fixes.

PreRelease

Gets the pre-release version identifier.

public string? PreRelease { get; }

Property Value

string

The pre-release identifier string without the leading hyphen, or null if this is a release version.

Remarks

Pre-release identifiers are dot-separated and may contain alphanumeric characters and hyphens, for example alpha.1, rc.2 or beta.

Prefix

Gets the version prefix in the format "MAJOR.MINOR.PATCH".

[JsonIgnore]
public string Prefix { get; }

Property Value

string

A string representing the core version without pre-release or metadata components.

Examples

SemVer.Parse("1.2.3-alpha+build").Prefix; // "1.2.3"

Methods

CompareTo(SemVer?)

Compares the current instance with another SemVer and returns an integer that indicates whether the current instance precedes, follows, or occurs in the same position in the sort order.

public int CompareTo(SemVer? other)

Parameters

other SemVer

The SemVer to compare with this instance.

Returns

int

A value that indicates the relative order of the objects being compared: Less than zero if this instance precedes other; Zero if they are equal; Greater than zero if this instance follows other.

Remarks

Comparison follows Semantic Versioning precedence rules:

  1. Compare major, minor, and patch versions numerically
  2. Pre-release versions have lower precedence than normal versions
  3. Pre-release identifiers are compared left to right: identifiers consisting only of ASCII digits are compared numerically (of any length, without overflow), a numeric identifier has lower precedence than an alphanumeric one, and alphanumeric identifiers are compared ordinally (ASCII)
  4. When all shared identifiers are equal, the version with more pre-release identifiers is greater
  5. Metadata is used only as a final tiebreaker (ordinal comparison)

Any instance is greater than null, so this method returns a positive value when other is null.

Equals(SemVer?)

Determines whether the specified SemVer is equal to the current instance.

public bool Equals(SemVer? other)

Parameters

other SemVer

The SemVer to compare with the current instance.

Returns

bool

true if CompareTo(SemVer?) returns zero, meaning all components including Metadata are equal; otherwise, false (including when other is null).

Equals(object?)

Determines whether the specified object is equal to the current instance.

public override bool Equals(object? obj)

Parameters

obj object

The object to compare with the current instance.

Returns

bool

true if obj is a SemVer equal to the current instance according to Equals(SemVer?); otherwise, false.

ExtractBuildNumber(string?)

Extracts a single numeric value from the specified input string.

public static int ExtractBuildNumber(string? input)

Parameters

input string

The string to extract a number from.

Returns

int

The numeric value if exactly one sequence of digits is found; otherwise, 0. Returns 0 if the input is null, empty, whitespace, or contains zero or multiple numbers.

Examples

SemVer.ExtractBuildNumber("alpha.123");   // 123
SemVer.ExtractBuildNumber("SNAPSHOT-12"); // 12
SemVer.ExtractBuildNumber("beta");        // 0
SemVer.ExtractBuildNumber("1.2.3");       // 0 (multiple numbers)
SemVer.ExtractBuildNumber(null);          // 0

Remarks

BuildNumberFromPreRelease and BuildNumberFromMetadata apply the same extraction rules to version components, except that they return 0 instead of throwing when the value is greater than int.MaxValue. This method can be called on any string.

Exceptions

OverflowException

Thrown when the single sequence of digits is greater than int.MaxValue.

FromSystemVersion(Version, bool)

Creates a SemVer instance from a System.Version.

public static SemVer FromSystemVersion(Version version, bool throwIfContainsRevision = false)

Parameters

version Version

The System.Version to convert.

throwIfContainsRevision bool

If true, throws an exception when the version has a revision greater than zero. Defaults to false.

Returns

SemVer

A SemVer with Major, Minor, and Patch (from Build) components and no pre-release or metadata.

Remarks

Maps System.Version Major.Minor.Build to SemVer Major.Minor.Patch. The revision component is ignored unless throwIfContainsRevision is true.

An undefined System.Version.Build (-1, as in new Version(1, 2)) maps to a Patch of 0, so the result is always a valid version that ToSystemVersion(bool, bool) can convert back.

Exceptions

ArgumentException

Thrown when throwIfContainsRevision is true and System.Version.Revision is greater than zero.

GetHashCode()

Serves as the default hash function.

public override int GetHashCode()

Returns

int

A hash code computed from Major, Minor, Patch, PreRelease and Metadata, consistent with Equals(SemVer?).

IsBetween(SemVer, SemVer)

Determines whether the current version is between two specified versions (exclusive).

public bool IsBetween(SemVer firstBound, SemVer secondBound)

Parameters

firstBound SemVer

The first boundary version.

secondBound SemVer

The second boundary version.

Returns

bool

true if this version is strictly between the two bounds; otherwise, false.

Examples

var version = SemVer.Parse("1.5.0");
version.IsBetween("1.0.0", "2.0.0"); // true
version.IsBetween("2.0.0", "1.0.0"); // true (bounds in any order)
version.IsBetween("1.0.0", "1.5.0"); // false (bounds are exclusive)

Remarks

Both bounds are exclusive and may be supplied in any order; the lower one is determined with the same precedence rules as CompareTo(SemVer?), so pre-release and metadata in the bounds are respected.

If both bounds are equal, returns true only if this version equals the bounds.

Parse(ReadOnlySpan<char>, IFormatProvider?)

Parses a span of characters representing a semantic version.

public static SemVer Parse(ReadOnlySpan<char> s, IFormatProvider? provider)

Parameters

s ReadOnlySpan<char>

The span of characters to parse.

provider IFormatProvider

Ignored; parsing is culture-independent.

Returns

SemVer

A SemVer equivalent to the version contained in s.

Remarks

This overload implements System.ISpanParsable<TSelf>. The span is converted to a string and parsed with Parse(string, IFormatProvider?).

Exceptions

ArgumentException

Thrown when s is not a valid semantic version string.

OverflowException

Thrown when the major, minor or patch component is greater than int.MaxValue.

Parse(string)

Parses a string representation of a semantic version.

public static SemVer Parse(string s)

Parameters

s string

The string to parse.

Returns

SemVer

A SemVer equivalent to the version contained in s.

Examples

var version = SemVer.Parse("1.2.3-alpha.1+build.456");

Remarks

Accepts version strings in the format MAJOR.MINOR.PATCH[-PRERELEASE][+METADATA] where MAJOR, MINOR, and PATCH are non-negative integers without leading zeros. Use TryParse(string?, out SemVer) when the input may be invalid.

Exceptions

ArgumentNullException

Thrown when s is null.

ArgumentException

Thrown when s is not a valid semantic version string.

OverflowException

Thrown when the major, minor or patch component is greater than int.MaxValue.

Parse(string, IFormatProvider?)

Parses a string representation of a semantic version.

public static SemVer Parse(string s, IFormatProvider? provider)

Parameters

s string

The string to parse.

provider IFormatProvider

Ignored; parsing is culture-independent.

Returns

SemVer

A SemVer equivalent to the version contained in s.

Remarks

This overload implements System.IParsable<TSelf>. Input is validated with the regular expression suggested by the Semantic Versioning 2.0.0 specification, so leading zeros in numeric components and empty pre-release or metadata segments are rejected.

Exceptions

ArgumentNullException

Thrown when s is null.

ArgumentException

Thrown when s is not a valid semantic version string.

OverflowException

Thrown when the major, minor or patch component is greater than int.MaxValue.

ToString()

Returns the string representation of this semantic version.

public override string ToString()

Returns

string

A string in the format MAJOR.MINOR.PATCH[-PRERELEASE][+METADATA], where the pre-release and metadata components are included only if present.

Examples

SemVer.Parse("1.2.3").ToString();               // "1.2.3"
SemVer.Parse("1.2.3-alpha").ToString();         // "1.2.3-alpha"
SemVer.Parse("1.2.3+build.1").ToString();       // "1.2.3+build.1"
SemVer.Parse("1.2.3-alpha+build.1").ToString(); // "1.2.3-alpha+build.1"

Remarks

For a version obtained by parsing, the result round-trips: parsing it again with Parse(string) produces an equal version.

ToSystemVersion(bool, bool)

Converts this semantic version to a System.Version instance.

public Version ToSystemVersion(bool throwIfContainsPreRelease = false, bool throwIfContainsMetadata = false)

Parameters

throwIfContainsPreRelease bool

If true, throws an exception when pre-release data is present. Defaults to false.

throwIfContainsMetadata bool

If true, throws an exception when metadata is present. Defaults to false.

Returns

Version

A System.Version with Major, Minor, and Build (from Patch) components.

Remarks

Maps SemVer Major.Minor.Patch to System.Version Major.Minor.Build. Pre-release and metadata information is lost in the conversion.

Exceptions

ArgumentException

Thrown when throwIfContainsPreRelease is true and pre-release data is present, or when throwIfContainsMetadata is true and metadata is present.

ArgumentOutOfRangeException

Thrown when Major, Minor or Patch is negative, which can only happen for an instance deserialized from JSON containing negative components.

TryParse(ReadOnlySpan<char>, out SemVer)

Tries to parse a span of characters representing a semantic version.

public static bool TryParse(ReadOnlySpan<char> s, out SemVer result)

Parameters

s ReadOnlySpan<char>

The span of characters to parse.

result SemVer

When this method returns, contains the SemVer equivalent to the version contained in s if the conversion succeeded, or null if it failed.

Returns

bool

true if s was converted successfully; otherwise, false.

Remarks

Never throws; returns false for invalid input, including components greater than int.MaxValue.

TryParse(ReadOnlySpan<char>, IFormatProvider?, out SemVer)

Tries to parse a span of characters representing a semantic version.

public static bool TryParse(ReadOnlySpan<char> s, IFormatProvider? provider, out SemVer result)

Parameters

s ReadOnlySpan<char>

The span of characters to parse.

provider IFormatProvider

Ignored; parsing is culture-independent.

result SemVer

When this method returns, contains the SemVer equivalent to the version contained in s if the conversion succeeded, or null if it failed.

Returns

bool

true if s was converted successfully; otherwise, false.

Remarks

This overload implements System.ISpanParsable<TSelf>. The span is converted to a string and parsed with TryParse(string?, IFormatProvider?, out SemVer).

TryParse(string?, out SemVer)

Tries to parse a string representation of a semantic version.

public static bool TryParse(string? s, out SemVer result)

Parameters

s string

The string to parse.

result SemVer

When this method returns, contains the SemVer equivalent to the version contained in s if the conversion succeeded, or null if it failed.

Returns

bool

true if s was converted successfully; otherwise, false.

Remarks

Never throws; returns false for invalid input, including components greater than int.MaxValue.

TryParse(string?, IFormatProvider?, out SemVer)

Tries to parse a string representation of a semantic version.

public static bool TryParse(string? s, IFormatProvider? provider, out SemVer result)

Parameters

s string

The string to parse.

provider IFormatProvider

Ignored; parsing is culture-independent.

result SemVer

When this method returns, contains the SemVer equivalent to the version contained in s if the conversion succeeded, or null if it failed.

Returns

bool

true if s was converted successfully; otherwise, false.

Remarks

This overload implements System.IParsable<TSelf> and never throws: it returns false when s is null, is not a valid semantic version string, or has a major, minor or patch component greater than int.MaxValue.

Operators

operator ==(SemVer?, SemVer?)

Determines whether two versions are equal.

public static bool operator ==(SemVer? left, SemVer? right)

Parameters

left SemVer

The first version to compare, or null.

right SemVer

The second version to compare, or null.

Returns

bool

true if both are null, or if left is not null and Equals(SemVer?) returns true; otherwise, false.

Remarks

This operator is null-safe and, like Equals(SemVer?), takes metadata into account.

operator >(SemVer?, SemVer?)

Determines whether left has higher precedence than right.

public static bool operator >(SemVer? left, SemVer? right)

Parameters

left SemVer

The version to compare, or null.

right SemVer

The version to compare against, or null.

Returns

bool

true if left compared with right using CompareTo(SemVer?) gives a value greater than zero; otherwise, false.

Remarks

This operator is null-safe: null precedes every version and two null operands are equal, consistent with CompareTo(SemVer?).

operator >=(SemVer?, SemVer?)

Determines whether left has the same or higher precedence than right.

public static bool operator >=(SemVer? left, SemVer? right)

Parameters

left SemVer

The version to compare, or null.

right SemVer

The version to compare against, or null.

Returns

bool

true if left compared with right using CompareTo(SemVer?) gives a value greater than or equal to zero; otherwise, false.

Remarks

This operator is null-safe: null precedes every version and two null operands are equal, consistent with CompareTo(SemVer?).

implicit operator string(SemVer)

Converts a SemVer to its string representation.

public static implicit operator string(SemVer semVer)

Parameters

semVer SemVer

The SemVer to convert. Must not be null.

Returns

string

The string representation of the semantic version, as returned by ToString().

Examples

string text = SemVer.Parse("1.2.3"); // "1.2.3"

implicit operator SemVer(string)

Converts the string representation of a semantic version to its SemVer equivalent.

public static implicit operator SemVer(string s)

Parameters

s string

The string representation of the semantic version.

Returns

SemVer

A SemVer object equivalent to the version contained in s.

Examples

SemVer version = "1.2.3-rc.1";

Remarks

Calls Parse(string), so invalid input throws. Use TryParse(string?, out SemVer) when the input may be untrusted.

Exceptions

ArgumentNullException

Thrown when s is null.

ArgumentException

Thrown when s is not a valid semantic version string.

OverflowException

Thrown when the major, minor or patch component is greater than int.MaxValue.

operator !=(SemVer?, SemVer?)

Determines whether two versions are not equal.

public static bool operator !=(SemVer? left, SemVer? right)

Parameters

left SemVer

The first version to compare, or null.

right SemVer

The second version to compare, or null.

Returns

bool

true if the versions are not equal according to the equality operator; otherwise, false.

Remarks

This operator is null-safe.

operator <(SemVer?, SemVer?)

Determines whether left has lower precedence than right.

public static bool operator <(SemVer? left, SemVer? right)

Parameters

left SemVer

The version to compare, or null.

right SemVer

The version to compare against, or null.

Returns

bool

true if left compared with right using CompareTo(SemVer?) gives a value less than zero; otherwise, false.

Remarks

This operator is null-safe: null precedes every version and two null operands are equal, consistent with CompareTo(SemVer?).

operator <=(SemVer?, SemVer?)

Determines whether left has the same or lower precedence than right.

public static bool operator <=(SemVer? left, SemVer? right)

Parameters

left SemVer

The version to compare, or null.

right SemVer

The version to compare against, or null.

Returns

bool

true if left compared with right using CompareTo(SemVer?) gives a value less than or equal to zero; otherwise, false.

Remarks

This operator is null-safe: null precedes every version and two null operands are equal, consistent with CompareTo(SemVer?).