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
-
objectSemVer
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
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 followsother.
Remarks
Comparison follows Semantic Versioning precedence rules:
- Compare major, minor, and patch versions numerically
- Pre-release versions have lower precedence than normal versions
- 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)
- When all shared identifiers are equal, the version with more pre-release identifiers is greater
- 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
Returns
- bool
true if CompareTo(SemVer?) returns zero, meaning all components including Metadata are equal; otherwise, false (including when
otheris null).
Equals(object?)
Determines whether the specified object is equal to the current instance.
public override bool Equals(object? obj)
Parameters
objobjectThe object to compare with the current instance.
Returns
- bool
true if
objis 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
inputstringThe string to extract a number from.
Returns
- int
The numeric value if exactly one sequence of digits is found; otherwise,
0. Returns0if 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
versionVersionThe System.Version to convert.
throwIfContainsRevisionboolIf 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
throwIfContainsRevisionis 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
Returns
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
sReadOnlySpan<char>The span of characters to parse.
providerIFormatProviderIgnored; parsing is culture-independent.
Returns
Remarks
This overload implements System.ISpanParsable<TSelf>. The span is converted to a string and parsed with Parse(string, IFormatProvider?).
Exceptions
- ArgumentException
Thrown when
sis 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
sstringThe string to parse.
Returns
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
sis null.- ArgumentException
Thrown when
sis 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
sstringThe string to parse.
providerIFormatProviderIgnored; parsing is culture-independent.
Returns
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
sis null.- ArgumentException
Thrown when
sis 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
throwIfContainsPreReleaseboolIf true, throws an exception when pre-release data is present. Defaults to false.
throwIfContainsMetadataboolIf 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
throwIfContainsPreReleaseis true and pre-release data is present, or whenthrowIfContainsMetadatais 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
sReadOnlySpan<char>The span of characters to parse.
resultSemVerWhen this method returns, contains the SemVer equivalent to the version contained in
sif the conversion succeeded, or null if it failed.
Returns
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
sReadOnlySpan<char>The span of characters to parse.
providerIFormatProviderIgnored; parsing is culture-independent.
resultSemVerWhen this method returns, contains the SemVer equivalent to the version contained in
sif the conversion succeeded, or null if it failed.
Returns
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
sstringThe string to parse.
resultSemVerWhen this method returns, contains the SemVer equivalent to the version contained in
sif the conversion succeeded, or null if it failed.
Returns
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
sstringThe string to parse.
providerIFormatProviderIgnored; parsing is culture-independent.
resultSemVerWhen this method returns, contains the SemVer equivalent to the version contained in
sif the conversion succeeded, or null if it failed.
Returns
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
leftSemVerThe first version to compare, or null.
rightSemVerThe second version to compare, or null.
Returns
- bool
true if both are null, or if
leftis 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
Returns
- bool
true if
leftcompared withrightusing 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
Returns
- bool
true if
leftcompared withrightusing 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
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
sstringThe string representation of the semantic version.
Returns
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
sis null.- ArgumentException
Thrown when
sis 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
leftSemVerThe first version to compare, or null.
rightSemVerThe second version to compare, or null.
Returns
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
Returns
- bool
true if
leftcompared withrightusing 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
Returns
- bool
true if
leftcompared withrightusing 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?).