This is a NuGet package containing a library that provides sort and compare functions for Semantic Version numbers.
You can install this package via CLI: dotnet add package DroidSolutions.Oss.SemanticVersion
.
If you want to install it in a project that is in a subdirectory give the path to the directory containing the csproj
file or the path to the csproj
like this: dotnet add src/MyProject package DroidSolutions.Oss.SemanticVersion
.
There is an interface ISemanticVersion
for which comparers are implemented. Just create a class and implement the interface.
You can also use the SemanticVersionObject
class that already implements the comparer with some neat and handy additions.
Additionally SemanticVersionObject
provides a Build
property containing any build metadata. As per specification build metadtaa data may only contain ASCII alphanumerics and hyphens [0-9A-Za-z-]
and can be appended at the end of the version with a plus sign +
.
When you create a new SemanticVersionObject
instance you can give the version number parts straight away.
SemanticVersionObject version = new(); // 1.0.0
SemanticVersionObject version = new(2); // 2.0.0
SemanticVersionObject version = new(1, 1); // 1.1.0
SemanticVersionObject version = new(1, 1, 1); // 1.1.1
SemanticVersionObject version = new(1, 1, 1, "alpha.1"); // 1.1.1-alpha.1
SemanticVersionObject version = new(1, 1, 1, "alpha.1", "298a915a"); // 1.1.1-alpha.1+298a915a
SemanticVersionObject version = new(1, 1, 1, null, "298a915a"); // 1.1.1+298a915a
There is also a static FromString
Method which will return you a SemanticVersionObject
instance from a version string.
var version = SemanticVersionObject.FromString("v1.0.0-beta.1+298a915a985daeb426a0fe7543917874d7fa2995");
There is a static method to take the version from a .NET Version
instance called FromVersion
. It takes the Version
instance as a parameter.
The second parameter controls how build and revision are used. The Version docs state, that revision should be used for assemblies that fix security holes but are otherwise the same. This would match the sense of the Patch
part of semantic version, so this is the default, setting the Revision
property to the patch version.
However when using the Version
build property in .csproj
the generated version in AssemblyInfo.cs
ends up in a way where patch version lands in the build property instead of revision. So when using the method with an Assembly version, you can pass true
to the method and the patch version will be read from the Build
property and Revision
is used for build version.
This retrieves the version from the current running application and returns a SemanticVersionObject
for it. For this Assembly.GetEntryAssembly()
is used.
You can generate a version string with the ToString
method:
SemanticVersionObject version = new() { Major = 1, Minor = 2, Patch = 3, PreRelease = "beta.1", Build = "298a915a" };
Console.WriteLine(version.ToString()); // v1.2.3-beta.1+298a915a
If you do not want the leading v
you can use the ToVersionString
method and give false for the withLeadingV
parameter:
var version = new SemanticVersionObject { Major = 1, Minor = 4, Patch = 0 };
Console.WriteLine(version.ToVersionString(false)); // 1.4.0
As mentioned a default comparer is included which allows to sort version descending to have the newest version first. You can use the Sort
LinQ method for this:
List<SemanticVersionObject> list = new()
{
SemanticVersionObject.FromString("1.0.0"),
SemanticVersionObject.FromString("1.1.1"),
SemanticVersionObject.FromString("1.1.0"),
SemanticVersionObject.FromString("0.9.0"),
};
list.Sort();
Assert.Equal(
new List<SemanticVersionObject>
{
SemanticVersionObject.FromString("1.1.1"),
SemanticVersionObject.FromString("1.1.0"),
SemanticVersionObject.FromString("1.0.0"),
SemanticVersionObject.FromString("0.9.0"),
},
list);
You can also use the Array Sort
method but then you have to specify the compare method yourself:
var list = new SemanticVersionObject[]
{
SemanticVersionObject.FromString("1.0.0"),
SemanticVersionObject.FromString("1.1.1"),
SemanticVersionObject.FromString("1.1.0"),
SemanticVersionObject.FromString("0.9.0"),
};
Array.Sort(list, SemanticVersionObject.SortVersionDescending());
Assert.Equal(
new List<SemanticVersionObject>
{
SemanticVersionObject.FromString("1.1.1"),
SemanticVersionObject.FromString("1.1.0"),
SemanticVersionObject.FromString("1.0.0"),
SemanticVersionObject.FromString("0.9.0"),
},
list);
The SemanticVersionObject
class implements the IComparable
interface so you can use the CompareTo
on every instance. Just pass another instance to it. The result is an integer that tells you, if the given instance is newer (1), equal (0) or older (-1).
SemanticVersionObject oldVersion = new(1, 0, 0);
SemanticVersionObject equalVersion = new(1, 0, 0);
SemanticVersionObject newVersion = new(1, 1, 0);
Console.WriteLine(oldVersion.CompareTo(newVersion)); // 1
Console.WriteLine(newVersion.CompareTo(oldVersion)); // -1
Console.WriteLine(oldVersion.CompareTo(equalVersion)); // 0
Sorting (and comparing) takes into account if there is a prerelease or not. For example consider this:
SemanticVersionObject x = new(1, 0, 0);
SemanticVersionObject y = new(1, 0, 0, "alpha.1");
Console.WriteLine(x.CompareTo(y)); // -1
Version without a prerelease are always newer if major, minor and patch are equal.
Also consider this:
SemanticVersionObject x = new(1, 0, 0, "beta.2");
SemanticVersionObject y = new(1, 0, 0, "beta.10");
Console.WriteLine(x.CompareTo(y)); // 1
Prereleases will be split into their parts and then will be compared. Each part must be separated with a dot. So for example beta is higher than alpha but just because b is later in the alphabet than a.
SemanticVersionObject x = new(1, 0, 0, "alpha.1");
SemanticVersionObject y = new(1, 0, 0, "beta.1");
SemanticVersionObject z = new(1, 0, 0, "develop.1");
Console.WriteLine(x.CompareTo(y)); // 1
Console.WriteLine(y.CompareTo(z)); // 1
As per spec build metadata is ignored when comparing.
List<SemanticVersionObject> list = new()
{
SemanticVersionObject.FromString("1.0.0+200"),
SemanticVersionObject.FromString("1.0.0+100"),
};
list.Sort();
Assert.Equal(
new List<SemanticVersionObject>
{
SemanticVersionObject.FromString("1.0.0+200"),
SemanticVersionObject.FromString("1.0.0+100"),
},
list);
You can use the IsNewerThan
or IsOlderThan
method if you need a boolean value.
var x = new SemanticVersionObject(2, 0, 0);
var y = new SemanticVersionObject(1, 0, 0);
var isNewer = x.IsNewerThan(y); // true
var isolder = y.IsOlderThan(x); // true
The methods only return true
if the given instance is newer/older. If they are both the same or the given compare version is null false
is returned.
You can use the IsPreRelease
method to determine if the given version is a pre release or a full semantic version.
SemanticVersionObject.FromString("v2.0.3").IsPreRelease(); // false
SemanticVersionObject.FromString("3.1.3-beta.12").IsPreRelease(); // true
If you want to add a feature or fix a bug, be sure to read the contribution guidelines first.
You'll need to install the .NET SDK which can be downloaded here.
To build the project, just run dotnet build
in the repository root. Tests can be executed with dotnet test
and code coverage is generated by either running dotnet test --collect:"XPlat Code Coverage"
or dotnet test /p:CollectCoverage=true
.