C#
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Object-Oriented C#
-
Section 4: Working with Data
-
Section 5: Error Handling
-
Section 6: Delegates and Events
-
Section 7: Async Programming
-
Section 8: More Language Features
-
Section 9: File I/O and Serialization
-
Section 10: Networking in .NET
-
Section 11: The .NET Ecosystem
-
Section 12: Memory and Performance
-
Section 13: Concurrency Beyond Async
-
Section 14: Reflection and Attributes
-
Section 15: Testing and Best Practices
-
Section 16: Design Patterns in C#
-
Section 17: Standard Library Deep Dive
-
Section 18: Data Structures and Algorithms in C#
-
Section 19: GUI and Desktop Development Overview
-
Section 20: Practical Projects
-
Section 21: More Practice Exercises
-
Section 22: More Standard Library and Text Processing
-
Section 23: More Design Patterns
-
Section 24: More Projects
-
Section 25: Interview Practice
-
Section 26: C# Keywords Reference (Modifiers)
-
Section 27: C# Keywords Reference (Statements)
-
Section 28: C# Keywords Reference (Operators)
-
Section 29: BCL: System.Collections.Generic
-
Section 30: BCL: System.Linq
-
Section 31: BCL: System.Threading
-
Section 32: BCL: System.IO
-
Section 33: BCL: System.Text and System.Text.Json
-
Section 34: BCL: System.Net.Http
-
Section 35: C# Language Specification Topics
-
Section 36: More Practice Exercises
-
Section 37: More Async Patterns
-
Section 38: More BCL: System.Reflection and System.Diagnostics
-
Section 39: Nullable Reference Types In Depth
-
Section 40: C# Records and Pattern Matching In Depth
-
Section 41: Dependency Injection Deep Dive
-
Section 42: More Interview and Whiteboard Practice
117: The Guid Type
Let's imagine we're building a system for a global e-commerce site. We've got multiple servers across different regions handling orders. Naturally, the first thing I'd do is give every order an ID so we can track it. My instinct—and yours probably—is to use an integer.
The problem with counting
I'll start with a simple Order class. I'll use a static counter to simulate how a database might auto-increment an ID.
public class Order
{
private static int _globalCounter = 0;
public int OrderId { get; }
public string Product { get; set; }
public Order(string product)
{
OrderId = ++_globalCounter;
Product = product;
}
}
// Simulation: Two different servers handling orders
var serverA_Order = new Order("Mechanical Keyboard");
var serverB_Order = new Order("Gaming Mouse");
This works fine on one server. But remember, we're distributed. If Server A and Server B both start up at the same time, they both start their counters at 0. Suddenly, I have two different orders with OrderId = 1. That's a nightmare for a database admin and a disaster for the customer who gets the wrong package. I can't rely on a central authority to hand out numbers in real-time without creating a massive bottleneck.
Something more random
I need an identifier that is unique not just on this machine, but across every machine in the world, without needing to check in with a central server first. I've seen people try to solve this by concatenating the server name, the date, and a random number into a string. It's messy, it's slow, and it's still technically possible to have a collision.
This is where I reach for the Guid type. Let's swap out that int and see what happens.
public class Order
{
public Guid OrderId { get; }
public string Product { get; set; }
public Order(string product)
{
OrderId = Guid.NewGuid();
Product = product;
}
}
var order1 = new Order("Mechanical Keyboard");
var order2 = new Order("Gaming Mouse");
Console.WriteLine($"Order 1 ID: {order1.OrderId}");
Console.WriteLine($"Order 2 ID: {order2.OrderId}");
When I run this, I don't get "1" and "2". I get something like f47ac10b-58cc-4372-a567-0e02b2c3d479. It's long, it's ugly, but it's a Globally Unique Identifier. The Guid.NewGuid() method generates a 128-bit integer that is, for all practical purposes, unique across the entire universe.
Wait, how unique is this actually?
I used to be skeptical about this. I wondered, "What if two servers generate the same Guid at the exact same nanosecond?"
Here is the reality: the probability of a collision is so astronomically low that you can effectively treat it as zero. You are more likely to be hit by a meteorite while winning the lottery than you are to generate a duplicate Guid in a standard application. It's designed specifically so that I can generate an ID on a laptop in Tokyo and you can generate one on a server in London, and we can be confident they won't clash when they hit the same database.
One thing I noticed while experimenting is that Guid is a value type (a struct), not a class. It's efficient, but it does have a few quirks. For instance, if I want to represent a "null" or empty Guid, I can't use null (unless I make it Guid?). Instead, there's a special constant:
Guid emptyId = Guid.Empty;
Console.WriteLine(emptyId); // Outputs: 00000000-0000-0000-0000-000000000000
I usually use Guid.Empty when I need a placeholder before a real ID has been assigned. It's a clean way to signal that the identifier hasn't been initialized yet.
📋 Practical Task
Build a Distributed Session Manager
Create a program that simulates a user login system for a distributed web app. You need to ensure that every user session is tracked with a unique identifier that cannot collide across different servers.
- Create a
UserSessionclass that stores aUsername(string) and aSessionId(Guid). - The
SessionIdshould be automatically generated usingGuid.NewGuid()when theUserSessionis instantiated. - In your
Mainmethod, create aList<UserSession>. - Add three different users to the list.
- Loop through the list and print the username and their unique Session ID to the console.
- To prove you understand the "empty" state, create one
UserSessionwhere the ID is manually set toGuid.Empty, and print it to show the difference between a generated ID and an empty one.
There are no comments for now.