CSharp - Other

BlockingCollection - Improves Multithreaded Performance

BlockingCollection<T> helps in producer-consumer scenarios for thread-safe data sharing.


Before (Manual Locking with Poor Performance)

Manually managing thread synchronization with locks leads to complex and inefficient code.

List<int> data = new List<int>();
object lockObj = new object();


void Producer()
{
    for (int i = 0; i < 5; i++)
    {
        lock (lockObj)
        {
            data.Add(i);
        }
    }
}


void Consumer()
{
    while (true)
    {
        int item;
        lock (lockObj)
        {
            if (data.Count == 0) continue;
            item = data[0];
            data.RemoveAt(0);
        }
        Console.WriteLine($"Consumed {item}");
    }
}


After (Efficient Producer-Consumer with BlockingCollection)

Using BlockingCollection<T>, thread synchronization is simpler and more efficient.

using System.Collections.Concurrent;


BlockingCollection<int> queue = new BlockingCollection<int>();


void Producer()
{
    for (int i = 0; i < 5; i++)
    {
        queue.Add(i);
    }
    queue.CompleteAdding();
}


void Consumer()
{
    foreach (var item in queue.GetConsumingEnumerable())
    {
        Console.WriteLine($"Consumed {item}");
    }
}


Building a Dynamic Predicate Based on Conditions

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;

class Product
{
    public string Name { get; set; }
    public int Price { get; set; }
}

class Program
{
    static void Main()
    {
        var products = new List<Product>
        {
            new Product { Name = "Laptop", Price = 1000 },
            new Product { Name = "Phone", Price = 700 },
            new Product { Name = "Tablet", Price = 400 }
        };

        string propertyToCheck = "Price";
        int minPrice = 500;

        var parameter = Expression.Parameter(typeof(Product), "p");
        var property = Expression.Property(parameter, propertyToCheck);
        var constant = Expression.Constant(minPrice);
        var condition = Expression.GreaterThan(property, constant);

        var lambda = Expression.Lambda<Func<Product, bool>>(condition, parameter);

        var filteredProducts = products.AsQueryable().Where(lambda).ToList();

        foreach (var product in filteredProducts)
        {
            Console.WriteLine($"{product.Name}, ${product.Price}");
        }
    }
}

C# Error with null-conditional operator and await

You can add ?? Operator so if ?. returns null task use CompletedTask instead.

await (this.MyObject?.MyMethod() ?? Task.CompletedTask)

Calculate Factorial Iteratively

A common task is computing the factorial of a number. This iterative approach keeps the code minimal.

int n = 5;
int factorial = 1;
for (int i = 1; i <= n; i++) factorial *= i;
Console.WriteLine(factorial);


Explanation: A simple for-loop multiplies numbers from 1 to n to compute the factorial, all within just three lines of code.

Caller Info Attributes

This feature is rarely used — but it's incredibly useful for debugging, logging, and even automatic edit tracking.


Suppose you want to see who called which function on which line in which file — then you can use:

public void Log(
    string message,
    [CallerMemberName] string memberName = "",
    [CallerFilePath] string filePath = "",
    [CallerLineNumber] int lineNumber = 0)
{
    Console.WriteLine($"{message} (Called from {memberName} in {filePath}, line {lineNumber})");
}


Now if you just say Log("Something went wrong");, that will also tell you where this call came from.

Database connection failed! (Called from Main in Program.cs, line 15)

Calling a method every x minutes

var startTimeSpan = TimeSpan.Zero;
var periodTimeSpan = TimeSpan.FromMinutes(5);

var timer = new System.Threading.Timer((e) =>
{
    MyMethod();   
}, null, startTimeSpan, periodTimeSpan);

Cannot add System.Data.Spatial to Domain classes

EF6 this has been renamed to System.Data.Entity.Spatial.

Centralized logging resource usage for all controller actions

.NET Framework


Create a Custom Action Filter

using System;
using System.Diagnostics;
using System.Web.Mvc;


public class ResourceUsageLoggingFilter : ActionFilterAttribute
{
    private Stopwatch _stopwatch;
    private long _startMemory;
    private TimeSpan _startCpuTime;


    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        // Start measuring CPU and memory
        _stopwatch = Stopwatch.StartNew();
        var process = Process.GetCurrentProcess();
        _startMemory = process.WorkingSet64;
        _startCpuTime = process.TotalProcessorTime;


        base.OnActionExecuting(filterContext);
    }


    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        _stopwatch.Stop();
        var process = Process.GetCurrentProcess();
        var endMemory = process.WorkingSet64;
        var endCpuTime = process.TotalProcessorTime;


        // Calculate memory and CPU usage
        var memoryUsedMb = (endMemory - _startMemory) / (1024 * 1024);
        var cpuUsedMs = (endCpuTime - _startCpuTime).TotalMilliseconds;


        // Log if usage exceeds thresholds
        if (memoryUsedMb > 50 || cpuUsedMs > 100) // Example thresholds
        {
            Debug.WriteLine($"High Resource Usage: Action: {filterContext.ActionDescriptor.ActionName}, " +
                            $"Memory: {memoryUsedMb} MB, CPU: {cpuUsedMs} ms, Duration: {_stopwatch.ElapsedMilliseconds} ms");
        }


        base.OnActionExecuted(filterContext);
    }
}


Register the filter in Global.asax

protected void Application_Start()
{
    GlobalFilters.Filters.Add(new ResourceUsageLoggingFilter());
}


Decorate individual controllers or actions with the filter

[ResourceUsageLoggingFilter]
public class HomeController : Controller
{
    public ActionResult Index()
    {
        return View();
    }
}


.NET Core


Create Middleware

public class ResourceUsageLoggingMiddleware
{
    private readonly RequestDelegate _next;


    public ResourceUsageLoggingMiddleware(RequestDelegate next)
    {
        _next = next;
    }


    public async Task InvokeAsync(HttpContext context)
    {
        var process = Process.GetCurrentProcess();
        var startMemory = process.WorkingSet64;
        var startCpuTime = process.TotalProcessorTime;
        var stopwatch = Stopwatch.StartNew();


        await _next(context);


        stopwatch.Stop();
        var endMemory = process.WorkingSet64;
        var endCpuTime = process.TotalProcessorTime;


        var memoryUsedMb = (endMemory - startMemory) / (1024 * 1024);
        var cpuUsedMs = (endCpuTime - startCpuTime).TotalMilliseconds;


        if (memoryUsedMb > 50 || cpuUsedMs > 100) // Example thresholds
        {
            Console.WriteLine($"High Resource Usage: Request: {context.Request.Path}, " +
                              $"Memory: {memoryUsedMb} MB, CPU: {cpuUsedMs} ms, Duration: {stopwatch.ElapsedMilliseconds} ms");
        }
    }
}


Register the middleware in Startup.cs

public void Configure(IApplicationBuilder app)
{
    app.UseMiddleware<ResourceUsageLoggingMiddleware>();
    app.UseRouting();
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
    });
}

Check if a Number is Prime

Determining if a number is prime can be elegantly solved in one line using LINQ.

int number = 29;
bool isPrime = Enumerable.Range(2, number - 2).All(i => number % i != 0);
Console.WriteLine(isPrime);


Explanation: Enumerable.Range(2, number - 2) generates a sequence from 2 to number - 1. The All method checks that no number in this range divides number evenly, confirming its primality.

Check if a String is a Palindrome

Checking whether a word is a palindrome can be done succinctly with LINQ.

string word = "radar";
bool isPalindrome = word.SequenceEqual(word.Reverse());
Console.WriteLine(isPalindrome);


Explanation: This code compares the original string with its reversed version using SequenceEqual. If they match, the string is a palindrome.

Chunks

Chunks are a way to split a collection into smaller groups or "chunks" of a specific size. This way you can break a long list of items into smaller groups to make it easier to work with.


Our Products list has 12 items. We can break it up into groups of 3 items and handle each chunk in a foreach:

IEnumerable<Product[]> chunks = ProductList.Products.Chunk(3);

foreach (Product[] chunk in chunks)
{
    foreach (Product product in chunk)
    {
        Console.WriteLine(product.Title);
    }
}


Benefits of chunks:

  1. Processing manageable parts is easier than dealing with a huge list.
  2. It manages memory more efficiently.
  3. Each chunk could be processed in parallel, which is a great improvement.
  4. It improves error handling. Errors in a certain chunk don't affect the other chunks. You can handle errors in a chunk, rather than on the whole list.
  5. Testing is made more efficient since you test a specific portion of the dataset.

Cloning an Array

int[] original = { 1, 2, 3, 4, 5 };
int[] cloned = (int[])original.Clone();
// Result: cloned = { 1, 2, 3, 4, 5 }