C#
.NET
programming
edge-cases
software-development

What's the strangest corner case you've seen in C or .NET?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

C sharp and .NET remove many low-level hazards, but they still contain corner cases that can surprise experienced developers. The interesting ones are not party tricks; they are the cases that expose hidden assumptions about time, equality, floating-point math, or deferred execution. Looking at a few representative examples is a practical way to build better defensive habits.

DateTime Kind Surprises

One of the most common strange corners is that two DateTime values can look the same but represent different assumptions about time zone handling.

csharp
1using System;
2
3var a = new DateTime(2026, 3, 7, 12, 0, 0, DateTimeKind.Utc);
4var b = new DateTime(2026, 3, 7, 12, 0, 0, DateTimeKind.Local);
5
6Console.WriteLine(a);
7Console.WriteLine(b);
8Console.WriteLine(a == b);

The values may display similarly, yet conversion behavior differs. Bugs appear when code assumes every DateTime is already normalized.

Floating-Point Equality Is Still a Trap

Even in managed code, floating-point arithmetic behaves like floating-point arithmetic.

csharp
double x = 0.1 + 0.2;
Console.WriteLine(x == 0.3);   // False
Console.WriteLine(x);

This is not a .NET bug, but it remains one of the most persistent real-world surprises in business logic and test assertions.

Deferred LINQ Execution

LINQ queries often execute later than people think.

csharp
1using System;
2using System.Linq;
3
4var numbers = new[] {1, 2, 3, 4};
5var query = numbers.Where(x => x % 2 == 0);
6
7Console.WriteLine(string.Join(", ", query));

That seems harmless, but if the source changes before enumeration, the result changes too. Many bugs come from assuming the query captured a snapshot instead of a recipe.

The fix is to materialize intentionally:

csharp
var snapshot = numbers.Where(x => x % 2 == 0).ToList();

foreach and Modified Collections

Mutating a collection while iterating it can throw immediately or create inconsistent logic depending on the exact collection type and operation.

csharp
1using System;
2using System.Collections.Generic;
3
4var items = new List<int> {1, 2, 3};
5
6foreach (var item in items)
7{
8    if (item == 2)
9        items.Add(4);
10}

This typically throws because the enumerator detects structural modification. The surprise is not that mutation is bad, but that people often reach this state through indirect helper methods rather than obvious inline edits.

String Comparison and Culture

Another strange corner appears when code assumes string comparisons are purely byte-oriented.

csharp
using System;

Console.WriteLine(string.Equals("FILE", "file", StringComparison.OrdinalIgnoreCase));

That is fine, but using culture-sensitive comparison accidentally in identifiers, file keys, or protocol values can produce hard-to-reason-about behavior. The corner case is not only language behavior, but choosing the wrong comparison mode for the domain.

null with Operator Overloads

Objects that overload equality can make null checks less obvious.

csharp
1public class Weird
2{
3    public static bool operator ==(Weird left, Weird right) => true;
4    public static bool operator !=(Weird left, Weird right) => false;
5}

That is an extreme example, but it shows why is null and is not null are often safer than == null for intent clarity in modern C sharp.

async Exceptions and Lost Context

One of the nastier practical cases is assuming an exception will surface where the method was called, even though the task was never awaited.

csharp
1using System;
2using System.Threading.Tasks;
3
4static async Task FailAsync()
5{
6    await Task.Delay(10);
7    throw new InvalidOperationException("boom");
8}

If the caller forgets to await FailAsync, the failure can surface later and far away from the originating logic.

The Practical Lesson

The strangest corners in .NET usually come from one of a few patterns:

  • hidden execution timing
  • implicit culture or timezone assumptions
  • numeric representation expectations
  • overloaded operator behavior

That means defensive engineering practices matter more than memorizing trivia.

Common Pitfalls

  • Treating DateTime values as interchangeable without checking Kind.
  • Using exact floating-point equality in business logic.
  • Forgetting that LINQ queries are deferred until enumeration.
  • Mutating collections during enumeration.
  • Choosing culture-sensitive string comparison for identifier-style values.

Summary

  • .NET corner cases usually expose hidden assumptions rather than framework defects.
  • Time, floating-point math, and deferred execution are the most common sources of surprise.
  • Prefer explicit comparison rules, explicit materialization, and explicit async handling.
  • Use is null style checks when operator overloads could obscure intent.
  • Defensive coding habits prevent more bugs than memorizing isolated quirks.

Course illustration
Course illustration

All Rights Reserved.