In the world of software development, maintaining data integrity and uniqueness is of utmost importance. One such unique identifier in C# is the Guid (Globally Unique Identifier) class. In this article, we will explore the Guid class in .NET, its features, and how we can implement it in our applications.

To download the source code for this article, you can visit our GitHub repository.

Let’s start exploring!

Support Code Maze on Patreon to get rid of ads and get the best discounts on our products!
Become a patron at Patreon!

What Is a Guid?

A Guid is a 128-bit value that possesses an exceedingly low probability of duplication. It is represented by a sequence of characters in the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.

Guid values are unique because they consist of 32 hexadecimal digits, resulting in an enormous number of possible combinations (approximately 3.4 * 10^38), making the likelihood of generating the same Guid practically impossible.

Usage of Guid in C#

The usage of Guid holds significant advantages in software development. We employ Guids when there is a need for absolute uniqueness and identification across various systems and applications. They serve as ideal choices for primary keys in databases, ensuring data integrity and avoiding conflicts during data merging.

However, a challenge we may face when using Guids as keys is the issue of fragmentation. The randomness of GUIDs can cause data to be scattered across various locations, impacting performance and making it less efficient for operations like indexing and searching.

Also, Guids are valuable in distributed systems, where we need to identify and track multiple entities uniquely. Their capability to generate unique identifiers on different devices and platforms makes them indispensable for scenarios such as message queues, data replication, and multi-tenant systems.

Furthermore, we use Guids extensively for user identification, filename generation, cryptography, and maintaining integrity in complex systems.

The wide range of applications and the guarantee of uniqueness make the Guid class a crucial component in modern software development.

How Do We Create a Guid in C#?

To explore the Guid class and its capabilities, let’s start by creating a console application project in Visual Studio. To do this, we either use the Project Wizard or type in the command window dotnet new console.

Let’s create our first random Guid

var randomGuid = Guid.NewGuid();
Console.WriteLine(randomGuid); // 5671c043-84d5-4da6-9863-c1a5710fca58

We have a new instance of the Guid class object by using the NewGuid() method. It is stored in the variable randomGuid and then we print the output to the console window.

We observe that the NewGuid() method creates a struct with a unique identifier value. This is a static method of the Guid class that produces a different outcome every time. 

It should be noted here that the GUIDs generated by .NET, specifically using UUID v4, are entirely random. This randomness can potentially lead to collisions when multiple workers within the same distributed system solely rely on the Guid.NewGuid() method for GUID generation. To address these concerns, we can introduce a dedicated mechanism in the distributed system that all workers adhere to for GUID generation.

Another way we can create a random Guid value is directly from the Visual Studio IDE. From the top bar menu, we click Tools ->Create GUID. In the next form, we choose the ‘Guid Format’ we desire, and we get a new value each time we click  ‘New GUID’.

Create a Guid With Specific Value

In .NET, many times we need to create a Guid object with a specific value:

var specificGuid = new Guid("3F2504E0-4F89-11D3-9A0C-0305E82C3301");

Here, we use the constructor of the Guid class that parses a given string and creates a Guid object based on the provided value. The result is the expected hexadecimal sequence.

The string value must be a valid representation of a Guid, meaning it should consist of 32 hexadecimal digits, grouped into five sections separated by hyphens. The case of the hexadecimal letters (A-F) in the string representation is not significant.

Moreover, if we pass a string value to the constructor that is not a valid Guid representation, an exception of type FormatException is thrown.

If we want to avoid this, we can use the TryParse() method:

public Guid TryParseGuid(string inputStringGuid)
{
    if (Guid.TryParse(inputStringGuid, out Guid outputGuid))
    {
        return outputGuid;
    }
    else
    {
        //handle non valid guid format.
        return Guid.Empty;
    }
}

The TryParse() method takes a string as an input argument. If the string is in a valid Guid format, it stores its value in the out variable and returns true. Otherwise, it returns false.

To learn more about the out keyword, check out our great article Difference Between Ref and Out Keywords in C#.

Create an Empty Guid in C#

An empty Guid is a special value of the Guid class in C#. It is a pre-defined instance that represents a “zero” or “empty” Guid, which is the default value for Guid instances when we do not assign a specific Guid:

var emptyGuid = new Guid();
Console.WriteLine(emptyGuid); // 00000000-0000-0000-0000-000000000000

Here, we observe that the emptyGuid variable has all of its bytes set to zero.

Moreover, we can get the same result if we set the variable emptyGuid equal to the Guid.Empty value:

var emptyGuid = Guid.Empty; // 00000000-0000-0000-0000-000000000000

Finally, we can see that the result is the same sequence of zeros. The empty Guid serves as a convenient default value for Guid instances and allows us to easily detect uninitialized or empty Guid instances in our code.

Guid Methods in C#

Now, we will delve into common methods and extensions available in the Guid class, unlocking the full potential of this essential component in C# development. By understanding these methods and extensions, we will have a comprehensive understanding of how to manipulate and work with Guids effectively in our C# applications.

The ToString() Method

The ToString() method converts the Guid object to a string representation:

public string GuidToString(Guid inputGuid)
{
    return inputGuid.ToString();
}

This implementation uses the “D” format by default. In addition, we can specify different formats, such as “N”, “B”, or “P”, using the Guid.ToString(string format) overload:

var inputGuid = Guid.NewGuid();

var guidStringD = inputGuid.ToString("D"); // f5060e47-6b59-4de6-aa2e-1f5e307e4d01

var guidStringN = inputGuid.ToString("N"); // f5060e476b594de6aa2e1f5e307e4d01

var guidStringB = inputGuid.ToString("B"); // {f5060e47-6b59-4de6-aa2e-1f5e307e4d01}

var guidStringP = inputGuid.ToString("P"); // (f5060e47-6b59-4de6-aa2e-1f5e307e4d01)

Here, we use the accepted format specifiers for the format parameter. The hyphens -, braces {}, and parentheses () appear as shown in each case.

Equality and Comparison Methods

We can compare Guid instances by using the Equals() method:

var guidA = new Guid("BE116B09-81D5-40F2-9A06-89E14066DFA6");
var guidB = new Guid("097D07C5-6897-4240-B9DE-D6179DCF6B6F");
var equalGuids = guidA.Equals(guidB); 

Console.WriteLine(equalGuids) // false

Here, we construct two different Guid instances and compare them using the Equals() method. This method returns a boolean value, and in this case, it returns false. 

The same can be performed using the equality operators == and !=. However, since Guid is a struct value type, equality operators and the Equals() method always have the same results. They compare the underlying bytes of the Guid to determine equality.

Let’s compare two Guid instances with the non-equal operator:

var nonEmptyGuid = new Guid("BE116B09-81D5-40F2-9A06-89E14066DFA6");
var equalGuids = nonEmptyGuid != Guid.Empty;

Console.WriteLine(equalGuids); // true

This check might be useful in cases where we want to see if a Guid does not have a value assigned.

The ToByteArray() Method

As we know, a Guid value consists of 16 bytes, each representing 8 bits, which collectively make up the 128 bits. The ToByteArray() method in the Guid struct returns a byte array representation of this value.

Let’s convert a Guid to a byte[]:

var inputGuid = Guid.NewGuid();
var byteArray = inputGuid.ToByteArray();

Console.WriteLine(BitConverter.ToString(byteArray)); // 31-A7-5A-C8-0C-24-D5-46-98-A8-ED-98-84-97-F8-03

First, we create a new Guid and we store its bytes in the byteArray variable. Then, we use the BitConverter.ToString() method to convert the byte array to a string representation for display.

The output is a string that represents the Guid value in its binary form, where each byte corresponds to two characters in the output string, and the bytes are separated by dashes (“-“).

The ToByteArray() method is useful in scenarios where we need to work with the Guid value at a lower level. These cases might be storing it in a database column that accepts binary data or performing custom byte-level operations on the Guid.

Similarly, we can make up a Guid with specific byte values using its constructor that takes as argument a byte array:

var byteArray = new byte[16] { 0xA1, 0x5F, 0x03, 0xC8, 0x23, 0x7B, 
0x42, 0x5C, 0xB3, 0xFF, 0x7D, 0xCB, 0x1C, 0x4A, 0x92, 0x00 };
var guidFromBytes = new Guid(byteArray);

Here, we have a byte[] that represents the 16 bytes of a Guid value. The constructor Guid(byte[]) takes the byte array as a parameter and creates a new Guid instance using the provided bytes.

It’s important to note that the byte array must be exactly 16 bytes long, as a Guid is a 128-bit value represented by 16 bytes. Otherwise, if the byte array doesn’t have exactly 16 elements, or if it is null, an exception will be thrown.

Constructing a Guid from a byte array can be useful when we want to reassemble a Guid from its individual byte components. For example, we may retrieve the bytes from a database or other storage medium and want to reconstruct the Guid object from its low-level form.

The TryWriteBytes() Method

A similar way to convert a Guid to byte format is with the usage of the TryWriteBytes() method:

var inputGuid = Guid.NewGuid();
Span<byte> dest = stackalloc byte[16];
inputGuid.TryWriteBytes(dest);

Console.WriteLine(BitConverter.ToString(dest.ToArray())); // 41-13-43-31-C1-14-C0-4C-AD-08-7E-A6-31-57-4C-18

First, we allocate a Span<byte> dest using stackalloc byte[16]. This reserves memory on the stack for 16 bytes, which we will use to store the byte representation of the new Guid.

Next, we call the TryWriteBytes method on the inputGuid to write the byte representation of the Guid into the dest span, which attempts to write the bytes of the Guid into the provided span, returning true if the write operation is successful.

Finally, we convert the byte span to an array using dest.ToArray()method, and then we use BitConverter.ToString() method to convert the byte array into a string representation. This results in a string with the hexadecimal values of the bytes separated by hyphens, as previously.

This code performs better in contrast to the ToByteArray() method solution, as stack allocation is generally faster than heap allocation. It involves a simple pointer adjustment rather than going through the heap memory management process.

We write the byte representation of the Guid directly into the stack-allocated span using TryWriteBytes()method. This avoids an additional memory copy operation that is required with the ToByteArray(), which creates a new byte array on the heap and copies the bytes from the Guid into it.

Conclusion

In this article, we explored the Guid class and its functionalities in C#. Furthermore, we examined different ways to create Guids. This included generating random Guids, constructing Guids from specific values or byte arrays, and working with common methods. With its extensive functionality, the Guid class empowers developers to implement robust identification and data integrity mechanisms in their C# applications.

Liked it? Take a second to support Code Maze on Patreon and get the ad free reading experience!
Become a patron at Patreon!