I recently noticed that when you construct a Guid from a byte array you might not get the exact same Guid you described, as it happens when it is constructed from a string. In particular the 8 bytes in the higher groups seem to be flipped (9dad turns to ad9d, etc).
[Fact]
public void TestGuidDiscrepancy()
{
var asString = "6ba7b810-9dad-11d1-80b4-00c04fd430c8";
var asBytes = new byte[]
{
0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1,
0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8
};
var guid1 = new Guid(asString);
var guid2 = new Guid(asBytes);
Assert.Equal(guid1.ToString(), guid2.ToString());
}
Uma.Uuid.Tests.GeneratorTest.TestGuidDiscrepancy
Assert.Equal() Failure
↓ (pos 0)
Expected: 6ba7b810-9dad-11d1-80b4-00c04fd430c8
Actual: 10b8a76b-ad9d-d111-80b4-00c04fd430c8
↑ (pos 0)
at Uma.Uuid.Tests.GeneratorTest.TestGuidDiscrepancy() in GeneratorTest.cs:line 28
md5-de20e1a0d0f948605f5bcfc80ad47cd7
$ dotnet --info
.NET Core SDK (reflecting any global.json):
Version: 2.2.203
Commit: e5bab63eca
Runtime Environment:
OS Name: ubuntu
OS Version: 16.04
OS Platform: Linux
RID: ubuntu.16.04-x64
Base Path: /usr/share/dotnet/sdk/2.2.203/
Host (useful for support):
Version: 2.2.4
Commit: f95848e524
.NET Core SDKs installed:
2.2.203 [/usr/share/dotnet/sdk]
.NET Core runtimes installed:
Microsoft.AspNetCore.All 2.2.4 [/usr/share/dotnet/shared/Microsoft.AspNetCore.All]
Microsoft.AspNetCore.App 2.2.4 [/usr/share/dotnet/shared/Microsoft.AspNetCore.App]
Microsoft.NETCore.App 2.2.4 [/usr/share/dotnet/shared/Microsoft.NETCore.App]
the first 12 letters (00000000-0000) bit is in fact a 8-byte integer and 4-byte integer, not just 8 and 4 1-byte data I believe. Probably endianess thing.
e.g. 0x6b, 0xa7, 0xb8, 0x10 is 0x6BA7B810 when interpreted as integer on big-endian machines but 0x10B8A76b when interpreted as integer on little-endian machines. (i.e. x86-64 and ARM machines)
https://en.m.wikipedia.org/wiki/Universally_unique_identifier See "format" section
Though, is there a standard on the endianess when interpreting GUID/UUIDs? that wikipedia article seem to state this:
The binary encoding of UUIDs varies between systems. Many systems encode the UUID entirely in a big-endian format.
But also:
...Other systems, notably Microsoft's marshalling of UUIDs in their COM/OLE libraries, use a mixed-endian format, whereby the first three components of the UUID are little-endian, and the last two are big-endian.
assuming it's the latter case I think the behaviour is expected, however could it be useful to provide a way to interpret the GUIDs encoded in the former format?
Spot on, that's exactly what it's doing. Thanks!
I really believe this behavior should be more clearly mentioned[1] in the docs, because the string-based constructor interprets all the supported input formats as a whole big-endian bitstream, and the Guid(byte[]) one only states that the input must be A 16-element byte array containing values with which to initialize the GUID. You just don't expect it to work so differently, a remark and a few examples would be great.
[1] It is mentioned in the remarks of the Guid(Int32, Int16, Int16, Byte, Byte, Byte, Byte, Byte, Byte, Byte, Byte) constructor, but in a rather vague way.
@1ma perhaps you'd like to offer a PR for the docs? https://github.com/dotnet/dotnet-api-docs
I'll see if I can manage.
Since the ctor is behaving as designed, and the proposed documentation update would be in a different repository, I'm going to go ahead and close this issue.