DEV Community

Cover image for 5 things you didn't know about Guid in C#
Davide Bellone
Davide Bellone

Posted on • Edited on • Originally published at code4it.dev

5 things you didn't know about Guid in C#

I'm pretty sure that you've already used Guids in C#, but have you ever stopped to think what they are under the hood?

#1: Guids have a fixed size

A GUID is a 128-bit integer (16 bytes) value. That means that there are more than 300,000,000,000,000,000,000,000,000,000,000,000,000 different values. A big number, isn't it?

It is virtually impossible to have duplicates, so it is safe to use.

Notice that an unsigned long is made of 64 bits: the biggest integral value that we can have has half of the bits of a Guid. The only type with the same size is decimal, but here we must consider both the sign and the precision.

#2: Guid is a struct

Just like int and short, a Guid is a struct and not an object.

public struct Guid : IComparable, IComparable, IEquatable, IFormattable
Enter fullscreen mode Exit fullscreen mode

Since this is a value type, if we pass it to a method, it won't change its value:

void Main()
{
    var initialGuid = Guid.NewGuid();
    Console.WriteLine("Before: "+ initialGuid);

    updateGuid(initialGuid);
    Console.WriteLine("After: "+ initialGuid);
}

void updateGuid(Guid tmpGuid){
    tmpGuid = Guid.NewGuid();
}
Enter fullscreen mode Exit fullscreen mode

will print

Before: d7241bf7-2778-42a9-a2e2-99228ada8c54
After: d7241bf7-2778-42a9-a2e2-99228ada8c54
Enter fullscreen mode Exit fullscreen mode

But, if we use the ref keyword

void Main()
{
    var initialGuid = Guid.NewGuid();
    Console.WriteLine("Before: "+initialGuid);

    updateGuidRef(ref initialGuid);
    Console.WriteLine("AfterRef: "+initialGuid);
}

void updateGuidRef( ref Guid tmpGuid)
{
    tmpGuid = Guid.NewGuid();
}
Enter fullscreen mode Exit fullscreen mode

we will have

Before: f93239da-4d20-4cb9-a8b7-df9002e4a042
AfterRef: b4274547-089b-42c9-a2d1-5d4d3a62f37a
Enter fullscreen mode Exit fullscreen mode

#3: You can create a Guid

For sure, the typical way of creating a Guid is using the static method Guid.NewGuid(). There are other ways to generate them.

If you want to create an empty Guid, you can use Guid.Empty: it will return a Guid composed only by 0s, like 00000000-0000-0000-0000-000000000000. Since we are talking about a struct, it doesn't make sense to have a null value, of course!

If you already have a GUID stored as string, you can parse it with Guid.Parse and Guid.TryParse. Just like for DateTime and for integers, the first one works only if the input string has a valid value, the second one tries to parse a value and assign it to a variable.

var guid1 = Guid.Parse("fc072692-d322-448b-9b1b-ba3443943579");
Console.WriteLine("Guid1: " + guid1);

Guid.TryParse("fc072692-d322-448b-9b1b-ba3443943579", out var guid2);
Console.WriteLine("Guid2: "+guid2);
Enter fullscreen mode Exit fullscreen mode

You can also use the simple constructor, like

var guid = new Guid("fc072692-d322-448b-9b1b-ba3443943579");
Enter fullscreen mode Exit fullscreen mode

or some of the more advanced constructors that operate at low level: for example, you can use a byte array as an input to the constructor, and have it converted to Guid.
Of course, the array must be of 16 bytes.

var bytes = new byte[16];
var guid = new Guid(bytes); // 00000000-0000-0000-0000-000000000000
Enter fullscreen mode Exit fullscreen mode

#4: A Guid has multiple formats

Now that you know that a Guid is made of 16 bytes, you can think "are the hyphens part of those bytes?".

Well, no: those are part of the default string representation of a Guid.

When using the ToString() method you can specify the format that you want. There are different types:

  • D: 32 digits, but with the hyphens. This is the default
  • N: 32 digits, without any other symbols
  • B: here we have the hyphens, and the string is enclosed in braces
  • P: similar to B, but with parentheses instead of braces
  • X: here we have the hexadecimal representation of the guid.

If we try to print the same Guid with the different formats, we can have something like

var tmpGuid = Guid.NewGuid();
Console.WriteLine("D \t"+tmpGuid.ToString("D"));
Console.WriteLine("N \t"+tmpGuid.ToString("N"));
Console.WriteLine("B \t"+tmpGuid.ToString("B"));
Console.WriteLine("P \t"+tmpGuid.ToString("P"));
Console.WriteLine("X \t"+tmpGuid.ToString("X"));
Enter fullscreen mode Exit fullscreen mode

that will print

D   e10deb88-171b-4c34-81f7-05fc17d16316
N   e10deb88171b4c3481f705fc17d16316
B   {e10deb88-171b-4c34-81f7-05fc17d16316}
P   (e10deb88-171b-4c34-81f7-05fc17d16316)
X   {0xe10deb88,0x171b,0x4c34,{0x81,0xf7,0x05,0xfc,0x17,0xd1,0x63,0x16}}
Enter fullscreen mode Exit fullscreen mode

Do you remember the Guid.Parse method that I showed before? Well, there is a secret sibling! Guid.ParseExact converts a string into a Guid only if it has the expected format.

So

Guid.ParseExact("(e10deb88-171b-4c34-81f7-05fc17d16316)", "P");
Enter fullscreen mode Exit fullscreen mode

will work, but

Guid.ParseExact("(e10deb88-171b-4c34-81f7-05fc17d16316)", "N");
Enter fullscreen mode Exit fullscreen mode

and

Guid.ParseExact("{e10deb88-171b-4c34-81f7-05fc17d16316}", "P");
Enter fullscreen mode Exit fullscreen mode

won't.

#5: Guids have NOT a fixed size

As I said, a Guid takes 16 bytes. So it's easy to suppose that sizeof(Guid) will return 16.

Well... no! It doesn't even compile, because _'Guid' does not have a predefined size; therefore you can use sizeofonly in an unsafe context.

That's because the size of a Guid is constant, but the memory allocated by the CLR isn't necessary constant (because for some architecture it can add a padding at the end, at the beginning or within the allocated memory).

So, you can see the value in 2 ways:
using the unsafe operator

unsafe
{
    sizeof(Guid);
}
Enter fullscreen mode Exit fullscreen mode

or using the Marshal.SizeOf method from System.Runtime.InteropServices.

Marshal.SizeOf()
Enter fullscreen mode Exit fullscreen mode

Wrapping up

Not so boring, isn't it? For sure, this is a great functionality of C#, and I hope I've triggered your curiosity about the hidden aspects of this language.

Happy coding!


Previously seen at Code4IT

Top comments (5)

Collapse
 
juankruiz profile image
Juan Carlos Ruiz Pacheco

God Job, I congratulate you for this post. Sharing and collect knowledge is important. Most of the times We tend to believe that everything is obvious and that everybody is going to understand what they are using, but the true is that is not the case. This is going to save tons of time and headaches to many people.

Collapse
 
bellonedavide profile image
Davide Bellone

Exactly! That's the point! When we do something that we think is simple, we forget about the complexity behind it. Sometimes it's fun to dive into details of something we use every day!

Collapse
 
elasticrash profile image
Stefanos Kouroupis

I am going to add a small detail, that hopefully will prevent headaches for people that work with Guids and ByteArrays.

Careful when you use Guid.ToByteArray the order of bytes is different from the string representation of the string value. Specifically if you want to create one with the same order you need to do the following (simplified)

        public static byte[] GenerateByteArray(byte[] g)
        {
            return new[]
                {g[3], g[2], g[1], g[0], g[5], g[4], g[7], g[6], g[8], g[9], g[10], g[11], g[12], g[13], g[14], g[15]};
        }
Collapse
 
adron profile image
Adron Hall

For context, one should also note the entire industry just uses the term UUID to define a similar thing. In normal fashion, Microsoft went off and renamed the things and added some object goo in .NET.

You can also, in .NET or other languages pull or build a specific UUID version too. Because they are specific and were made with different contexts. For example, with Go check out these options...

compositecode.blog/2018/05/14/uuid...

More details include the Microsoft claim on their use as synonyms within the IETF TFC 4122:

"A Universally Unique IDentifier (UUID) URN Namespace": "a Uniform Resource Name namespace for UUIDs (Universally Unique IDentifier), also known as GUIDs (Globally Unique IDentifier)."

In the ITU-T Recommendation X.667:

"UUIDs are also known as Globally Unique Identifiers (GUIDs), but this term is not used in this Recommendation."

MS claiming a GUID is specified by the UUID RFC: "In Microsoft Windows programming and in Windows operating systems, a globally unique identifier (GUID), as specified in [RFC4122], is ... The term universally unique identifier (UUID) is sometimes used in Windows protocol specifications as a synonym for GUID."

Just one of those Microsoft things. ;)

Collapse
 
michalmaminski profile image
MichaƂ MamiƄski

Essential knowledge of GUID. Well done