Uma.Uuid
0.1.0
dotnet add package Uma.Uuid --version 0.1.0
NuGet\Install-Package Uma.Uuid -Version 0.1.0
<PackageReference Include="Uma.Uuid" Version="0.1.0" />
paket add Uma.Uuid --version 0.1.0
#r "nuget: Uma.Uuid, 0.1.0"
// Install Uma.Uuid as a Cake Addin #addin nuget:?package=Uma.Uuid&version=0.1.0 // Install Uma.Uuid as a Cake Tool #tool nuget:?package=Uma.Uuid&version=0.1.0
Uma.Uuid
A port of the uma/uuid library to C#, an RFC 4122 compliant implementation of Universally Unique Identifiers.
This software is in alpha stage.
Installation
TODO publish to NuGet
How does Uma.Uuid
compare to the standard Guid
class?
There are three key benefits:
Generation decoupled from the value object
Withs Guids you generate new value objects calling the static Guid.NewGuid()
method. With Uma.Uuid
generation is
segregated into a IUuidGenerator
interface, meaning you can easily swap implementations and generation strategies
in your services.
Multiple generation strategies
Guid.NewGuid()
always generates version 4 Guids, which are not ideal especially if you use them as table
primary keys in a relational database.
Uma.Uuid
provides several RFC 4122 compliant generators (including version 4) plus Jimmy Nilsson's COMB Guid generator
and a SequentialGenerator for testing scenarios where determinism might be preferred.
Consistent Big-Endian serialization
When converting a Guid
to a 16-byte array (for instance, to store it in a table in compressed form) with
Guid.ToByteArray()
it does something unexpected: it serializes the higher 8 bytes, belonging to the first 3 groups in
little-endian form, while the lower 8 are serialized in big endian. Moreover it does not exhibit this behaviour when the
same object is serialized with Guid.ToString()
.
In contrast Uuid.ToByteArray()
and Uuid.ToString()
always serialize the underlying bytes in Big-Endian, which is
specially important for COMB Uuids, otherwise their "monotonically increasing" property would be lost.
This can be illustrated with the following xUnit test (that is actually present in the library's test suite):
[Fact]
public void TestUuidGuidDivergence()
{
var bytes = new byte[]
{
0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10
};
var uuid = new Uuid(bytes);
var guid = new Guid(bytes);
Assert.Equal("01234567-89ab-cdef-fedc-ba9876543210", uuid.ToString());
Assert.Equal("67452301-ab89-efcd-fedc-ba9876543210", guid.ToString());
}
FAQ
How do you convert an Uuid
to a plain old Guid
?
The value object has a helper method for that, Uuid.ToGuid()
.
Which UUID generator is the "best"?
Hands down the CombGenerator
, for the reasons exposed by Jimmy Nilsson in his classical article The Cost of GUIDs as Primary Keys.
Can I write my own generators?
Yes, just write an implementation of the IUuidGenerator
. Here's sample implementation that could be useful in a testing environment:
using Uma.Uuid;
namespace Uuid.Sample
{
public class DeterministicGenerator : IUuidGenerator
{
private readonly Uuid _uuid;
public DeterministicGenerator(Uma.Uuid.Uuid uuid)
{
_uuid = uuid;
}
public Uuid NewUuid(string name = null)
{
return _uuid;
}
}
}
Benchmarking
There is BenchmarkDotNet suite under Uma.Uuid.Benchmarks
. Currently Guid
is much more faster than Uuid
when
constructing from a string, but more or less on par when constructing from a 16-byte array.
On the other hand all generators run generally faster than Guid.NewGuid
. Here's a sample run on my laptop:
// * Summary *
BenchmarkDotNet=v0.11.5, OS=ubuntu 18.04
Intel Pentium CPU N4200 1.10GHz, 1 CPU, 4 logical and 4 physical cores
.NET Core SDK=2.2.204
[Host] : .NET Core 2.2.5 (CoreCLR 4.6.27617.05, CoreFX 4.6.27618.01), 64bit RyuJIT
DefaultJob : .NET Core 2.2.5 (CoreCLR 4.6.27617.05, CoreFX 4.6.27618.01), 64bit RyuJIT
| Method | Mean | Error | StdDev | Median | Ratio | RatioSD | Gen 0 | Gen 1 | Gen 2 | Allocated |
|--------------------- |-----------:|---------:|---------:|-----------:|------:|--------:|-------:|------:|------:|----------:|
| CreateGuidFromString | 718.1 ns | 14.63 ns | 32.73 ns | 706.1 ns | 1.00 | 0.00 | - | - | - | - |
| CreateUuidFromString | 3,555.1 ns | 68.76 ns | 64.32 ns | 3,512.0 ns | 4.85 | 0.23 | 0.3014 | - | - | 160 B |
| Method | Mean | Error | StdDev | Median | Ratio | RatioSD | Gen 0 | Gen 1 | Gen 2 | Allocated |
|------------------------ |---------:|----------:|----------:|---------:|------:|--------:|-------:|------:|------:|----------:|
| CreateGuidFromByteArray | 22.55 ns | 0.0223 ns | 0.0174 ns | 22.55 ns | 1.00 | 0.00 | - | - | - | - |
| CreateUuidFromByteArray | 31.45 ns | 1.9380 ns | 5.5605 ns | 29.27 ns | 1.25 | 0.13 | 0.0457 | - | - | 24 B |
| Method | Mean | Error | StdDev | Ratio | RatioSD | Gen 0 | Gen 1 | Gen 2 | Allocated |
|------------------- |-----------:|----------:|----------:|------:|--------:|-------:|------:|------:|----------:|
| GenerateGuid | 3,023.4 ns | 21.271 ns | 18.856 ns | 1.00 | 0.00 | - | - | - | - |
| GenerateComb | 2,181.5 ns | 4.718 ns | 3.940 ns | 0.72 | 0.00 | 0.3052 | - | - | 160 B |
| GenerateVersion4 | 311.9 ns | 5.909 ns | 6.323 ns | 0.10 | 0.00 | 0.1216 | - | - | 64 B |
| GenerateVersion5 | 1,885.8 ns | 57.314 ns | 56.290 ns | 0.63 | 0.02 | 0.4559 | - | - | 240 B |
| GenerateSequential | 113.1 ns | 2.242 ns | 5.707 ns | 0.04 | 0.00 | 0.1067 | - | - | 56 B |
Contributing
This project is my first foray into C# and the .NET ecosystem. Suggestions, issues and PRs are always welcome.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
.NET Core | netcoreapp2.2 is compatible. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
-
.NETCoreApp 2.2
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
0.1.0 | 3,555 | 5/19/2019 |