Tips for optimizing C/.NET programs
Data Structures & Algorithms practice on Codemia
Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.
Introduction
Optimizing C# and .NET code starts with one rule: measure before you change anything. The runtime, JIT, garbage collector, and libraries are already highly optimized, so performance work is most effective when it targets a proven bottleneck instead of general intuition.
Start With Measurement
Before rewriting code, use a profiler or at least a reproducible benchmark. Without that, it is easy to make code harder to read for no meaningful gain.
For real applications, measure:
- CPU hotspots
- allocation rate
- GC pressure
- database or network latency
- lock contention
A slow request is often not slow because of arithmetic. It is slow because of I/O, allocation churn, or excessive synchronization.
Reduce Unnecessary Allocations
Allocation-heavy code puts more pressure on the garbage collector. One common example is repeated string concatenation in loops.
For small one-off cases, normal string interpolation is fine. For repeated accumulation, StringBuilder is usually the better choice.
Choose Data Structures Carefully
Algorithm and data-structure choices often matter more than micro-optimizations.
Examples:
- use
Dictionary<TKey, TValue>for key lookups instead of repeated linear scans - use
HashSet<T>when membership testing matters - use arrays when size is fixed and indexed access is the main operation
If a hot path does repeated List<T>.Contains, replacing it with a HashSet<T> can outperform many low-level tweaks combined.
Be Careful With LINQ on Hot Paths
LINQ is expressive and often perfectly fine, but in tight loops or large pipelines it can create extra allocations or repeated enumeration if used carelessly.
Readable code:
Hot-path alternative when profiling proves it matters:
Do not replace all LINQ preemptively. Replace it only when the measured cost matters.
Avoid Blocking and Over-Synchronization
Performance issues in .NET programs are often about waiting, not computing.
Examples include:
- blocking on async work with
.Resultor.Wait() - serializing too much work through one lock
- holding locks during I/O
If the code is I/O-bound, async patterns can improve throughput far more than CPU-level tweaks.
Cache Only When It Helps
Caching can be powerful, but it is not free. It increases memory use and invalidation complexity.
Cache results when:
- the data is expensive to compute or fetch
- reuse is high
- staleness rules are clear
Do not add caching just because a method looks "important." Measure the benefit.
Common Pitfalls
The most common mistake is optimizing without profiling, which often targets the wrong part of the program.
Another mistake is focusing on tiny language-level tweaks while ignoring larger wins such as algorithm choice, database access patterns, or allocation churn.
A third pitfall is making code unreadable for a theoretical speedup that never shows up in production measurements.
A fourth pitfall is skipping after-change measurement and assuming an optimization helped just because it looks lower level.
Summary
- Measure before optimizing.
- Reduce allocations and choose data structures that match the workload.
- Treat LINQ, strings, and collections as optimization targets only when profiling identifies them.
- Many real .NET performance problems are about I/O, blocking, or synchronization rather than raw CPU work.
- Prefer changes that improve both performance and maintainability when possible.
Related reading
- to drawRect or not to drawRect when should one use drawRect/Core Graphics vs subviews/images and why?
- To return IQueryableT or not return IQueryableT
- .toArraynew MyClass0 or .toArraynew MyClassmyList.size?
- Toilet Seat Algorithm
- To CurrentThread.Abort or not to CurrentThread.Abort
- Transactions in .net
- Tomcat takes too much time to start - Java SecureRandom
- Tomcat threads vs Java threads

DSA Fundamentals
Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
Data Structures & Algorithms practice on Codemia
Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.