REST Tip – Use HATEOAS to guide the client
HATEOAS = Hypermedia as the Engine of Application State
📦 Instead of sending just data, include actions
🧠 Why?
• Makes APIs discoverable
• Reduces hard-coded logic on the client
• Enables better versioning and evolution
Posts by Code Whisper
Each class type serves a purpose.
Use them wisely to keep your codebase clean, maintainable, and SOLID.
#CSharp #DevCommunity #CleanCode
6. Nested Classes
Class inside another class.
Can be used for tight coupling (e.g., helper classes for outer class).
5. Partial Classes
Split one class across multiple files.
Great for large codebases or designer-generated code.
4. Sealed Classes
Can’t be inherited.
Used when you want to restrict extension.
3. Static Classes
Only contains static members. Can’t be instantiated or inherited.
Perfect for utility/helper methods.
2. Abstract Classes
Use abstract when the class is meant to be inherited, not instantiated.
It can have both abstract (unimplemented) and concrete (implemented) methods.
1. Regular Classes
The most common type: public class MyClass { }
Supports inheritance, encapsulation, constructors, methods, fields.
Can be instantiated with new.
Let’s talk about C# class types — a solid foundation for OOP in .NET.
You’ll find more than just “class” in C#. Let’s dive into the types you can define and use.
HTTP Tip
Idempotent methods can be safely retried without causing side effects.
🔹 GET, PUT, DELETE, HEAD, OPTIONS → Idempotent
🔹 POST → NOT idempotent
🧠 Why?
Using the correct method:
▪️ Makes APIs predictable
▪️ Enables retries in network failures
▪️ Helps with caching, monitoring, and debugging
🧠 Why?
• Scalar functions run row by row = performance bottleneck
• Use inline expressions, computed columns, or TVFs (table-valued functions) for better scalability
SQL Tip – Avoid Scalar Functions in SELECT for Performance
🚫 Bad (Scalar function kills performance on large data)
✅ Good (Inline logic or apply in WHERE/CTE for better performance)
Example:
.NET DI Lifetime Tips:
🔹 Singleton - one of instance for entire app
🔹 Scoped - one instance per request
🔹 Transient - new instance every time
🚨 Be careful:
- Dont inject Scoped/Transient into Singleton (causes bugs/memory leaks)
- Use Singleton only for stateless or thread-safe services.
LINQ Tip:
Use ToList() after filtering, not before
Why?
🔹 First version loads everything into memory before filtering
🔹 Second version filters at source, better for DB or large collections
🔹 Especially important when using EF Core or APIs with IQueryable
🔹 Performance: Asynchronous iteration prevents thread blocking, keeping your app responsive.
🔹 Clean Code: No need for callbacks or complex state management like with traditional async operations.
🔹 await foreach: Asynchronously iterates over the items one by one, allowing for non-blocking execution while the data is being fetched.
Benefits:
🔹Memory Efficiency: Only one item is in memory at a time, so it’s ideal for processing large datasets or streams.
Explanation:
IAsyncEnumerable<T>: Enables you to stream data asynchronously without blocking threads.
🔹 Use yield return to return items one at a time.
🔹 Data is fetched lazily, so you only process what you need.
Efficient Async Data Streaming with IAsyncEnumerable<T>
Scenario:
You need to process a large dataset (e.g., database records, file lines, etc.), but you don’t want to load everything into memory at once. Using IAsyncEnumerable<T> lets you stream data asynchronously with minimal memory usage.
🔹 What is Queue<T>?
Queue<T> is a First-In-First-Out (FIFO) collection in C#.
It means the first item you add is the first one to be removed.
When to use?
- Task scheduling
- Print jobs
- Message handling
- Breadth-first search (BFS) in graphs
Example:
SQL Tip:
Always monitor and maintain your indexes.
Unused or duplicate indexes = slower writes and wasted space.
Why?
- Clean indexes = faster inserts/updates
- Less I/O, better performance
🔍 Use this to find unused indexes in SQL Server
Csharp Tip:
Use Span<T> for high-performance, allocation-free array slicing. Avoid ToList() when you don’t need it!
Why?
🔹 Zero allocations
🔹 Lightning-fast memory access
🔹 Perfect for performance-critical code
#csharp #dotnet
LINQ Trip:
Use GroupJoin for efficient one-to-many relationships instead of nested loops.
Why?
🔹 Cleaner than SelectMany + Where
🔹 Ideal for creating master-detail structures in memory
SQL Tip:
Use CROSS APPLY for row-wise calculations or to invoke table-valued functions per row.
Why?
🔹Powerful for row-by-row subqueries
🔹Cleaner & faster than correlated subqueries in many cases
Csharp Tip:
Use async Task for methods so exceptions can be awaited and handled properly.
Pro tip: Use async void only for UI event handlers.
Pass by Value vs Pass by Reference
🔹 Pass by Value: A copy of the value is passed to the function. Changes inside the function don’t affect the original variable.
🔹 Pass by Reference: The memory address (reference) is passed. Changes inside the function do affect the original variable.
SQL Tip:
Use EXISTS instead of COUNT(*) > 0 for better performance when checking if rows exist.
✅ EXISTS stops at the first match.
❌ COUNT(*) scans the whole table.
Faster checks = faster queries ⚡
How does it work?
Instead of sending 1 SQL query per entity (slow), BulkUpdate:
✅ Builds a temporary SQL table
✅ Pushes all data into it in one batch
✅ Runs a single efficient UPDATE JOIN on the real table
✅ Drops the temp table after update
Result: Thousands of updates in milliseconds ⚡
EF Core Tip – Bulk Update:
Need to update thousands of rows? Avoid looping with .SaveChanges() in EF Core — it's slow.
Use a bulk update library like EFCore.BulkExtensions for massive performance gains.
Bonus: Works for Insert, Delete, Merge too.
Csharp Tip:
Extract magic values into constants to improve readability and maintainability.
Cleaner code = easier maintenance!
C# Trick:
Use Dictionary for fast lookups instead of looping!
Instead of searching a list repeatedly, store key-value pairs in a dictionary for O(1) access.