← Back to Articles         
Real-Time Scenarios and Coding

Real-Time Scenarios and Coding

Published on 12 Oct 2026     13 min read C# Collections & Generics
Real-Time Scenarios and Coding

These questions focus on practical collection operations, LINQ, Dictionary, grouping, sorting, the Repository Pattern, and thread-safe caching in ASP.NET Core.

1. How do you remove duplicate integers from a list?

Explanation

We can remove duplicate integers using:

  • Distinct() — LINQ method that returns unique elements.

  • HashSet<T> — Automatically stores unique elements.

Example Program

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

List<int> numbers = new() { 10, 20, 10, 30, 20, 40 };

List<int> uniqueNumbers = numbers
    .Distinct()
    .ToList();

Console.WriteLine(string.Join(", ", uniqueNumbers));

Output:

10, 20, 30, 40

Explanation of Code

  1. Distinct() eliminates duplicate values using equality comparison.

  2. ToList() converts the result into a new list.

  3. The original list remains unchanged.

Alternative: Using HashSet

HashSet<int> uniqueNumbers = new(numbers);

Diagram

Original List
[10, 20, 10, 30, 20, 40]
          |
          v
       Distinct()
          |
          v
[10, 20, 30, 40]

Key Points

  • Distinct() is the simplest LINQ solution.

  • HashSet<T> prevents duplicate values.

  • Average time complexity is O(n) with hash-based equality.

  • Distinct() preserves first-occurrence order in current .NET implementations, but its API does not guarantee ordering. Sort explicitly if order matters.

 

2. How do you find the second-highest number in a list?

Explanation

To find the second-highest distinct number:

  1. Remove duplicates.

  2. Sort numbers in descending order.

  3. Skip the highest number.

  4. Return the next number.

Example Program

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

List<int> numbers = new()
{
    10, 50, 30, 50, 40
};

int? secondHighest = numbers
    .Distinct()
    .OrderByDescending(x => x)
    .Skip(1)
    .Select(x => (int?)x)
    .FirstOrDefault();

Console.WriteLine(secondHighest?.ToString() ?? "Not found");

Output:

40

Diagram

Original
[10, 50, 30, 50, 40]
          |
          v
       Distinct()
[10, 50, 30, 40]
          |
          v
  OrderByDescending()
[50, 40, 30, 10]
          |
          v
        Skip(1)
[40, 30, 10]
          |
          v
     FirstOrDefault()
          |
          v
         40

Key Points

  • Distinct() removes duplicate numbers.

  • OrderByDescending() sorts from highest to lowest.

  • Skip(1) skips the highest distinct number.

  • Sorting takes O(n log n) time.

  • If fewer than two distinct numbers exist, the result is null.

  • An O(n) solution is possible by tracking the highest and second-highest values in one pass.

 

3. How do you count the frequency of each word using Dictionary?

Explanation

A Dictionary<string, int> stores each word as a key and its occurrence count as the value.

Key       Value
----------------
CSharp      3
SQL         2
Azure       1

Example Program

using System;
using System.Collections.Generic;

string[] words =
{
    "CSharp", "SQL", "CSharp",
    "Azure", "SQL", "CSharp"
};

Dictionary<string, int> frequency = new();

foreach (string word in words)
{
    if (frequency.ContainsKey(word))
    {
        frequency[word]++;
    }
    else
    {
        frequency[word] = 1;
    }
}

foreach (var item in frequency)
{
    Console.WriteLine($"{item.Key}: {item.Value}");
}

Output:

CSharp: 3
SQL: 2
Azure: 1

Explanation of Code

  • ContainsKey() checks whether the word already exists.

  • If it exists, increment the count.

  • Otherwise, insert the word with a count of 1.

Alternative: Using LINQ

var frequency = words
    .GroupBy(x => x)
    .ToDictionary(g => g.Key, g => g.Count());

Key Points

  • Dictionary stores unique keys.

  • Average lookup and update complexity is O(1).

  • Overall counting takes O(n) on average.

  • Use StringComparer.OrdinalIgnoreCase when case-insensitive counting is required.

  • Useful for log analysis, text processing, and reporting.

 

4. How do you find duplicate elements in a collection?

Explanation

We can use LINQ GroupBy() to group identical values and select groups whose count is greater than one.

Example Program

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

List<int> numbers = new()
{
    10, 20, 30, 20, 40, 10, 50
};

var duplicates = numbers
    .GroupBy(x => x)
    .Where(g => g.Count() > 1)
    .Select(g => new
    {
        Number = g.Key,
        Count = g.Count()
    });

foreach (var item in duplicates)
{
    Console.WriteLine($"{item.Number}: {item.Count}");
}

Output:

10: 2
20: 2

Diagram

Input
[10, 20, 30, 20, 40, 10, 50]
              |
              v
           GroupBy()
              |
              v
10 -> 2
20 -> 2
30 -> 1
40 -> 1
50 -> 1
              |
              v
        Count() > 1
              |
              v
         10, 20

Key Points

  • GroupBy() groups matching elements.

  • Where() filters groups containing duplicates.

  • Count() determines the number of occurrences.

  • Hash-based grouping is O(n) on average.

  • Useful for identifying duplicate IDs, transaction references, or records.

 

5. How do you group employees by department?

Explanation

LINQ GroupBy() groups employees based on a common property, such as Department.

Example Program

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

List<Employee> employees = new()
{
    new Employee { Id = 1, Name = "John", Department = "IT" },
    new Employee { Id = 2, Name = "David", Department = "HR" },
    new Employee { Id = 3, Name = "Peter", Department = "IT" },
    new Employee { Id = 4, Name = "Mary", Department = "HR" }
};

var groups = employees
    .GroupBy(e => e.Department);

foreach (var group in groups)
{
    Console.WriteLine($"Department: {group.Key}");

    foreach (var employee in group)
    {
        Console.WriteLine(employee.Name);
    }
}

class Employee
{
    public int Id { get; set; }
    public string Name { get; set; } = "";
    public string Department { get; set; } = "";
}

Output:

Department: IT
John
Peter
Department: HR
David
Mary

Diagram

Employees
    |
    v
GroupBy(Department)
    |
    +---- IT
    |      |
    |      +---- John
    |      +---- Peter
    |
    +---- HR
           |
           +---- David
           +---- Mary

Explanation of Code

  • GroupBy(e => e.Department) creates groups by department.

  • group.Key represents the department name.

  • Each group contains the employees belonging to that department.

Key Points

  • GroupBy() is used to organize records by a common property.

  • group.Key identifies the group.

  • Multiple properties can be used for grouping.

  • Useful for department reports, sales summaries, and dashboards.

  • In EF Core, grouping and aggregation can often be executed directly in SQL Server.

 

6. How do you sort employees by salary and name?

Explanation

Use OrderBy() for primary sorting and ThenBy() for secondary sorting.

Suppose the requirement is:

  • Salary — highest to lowest.

  • Name — alphabetical when salaries are equal.

Example Program

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

List<Employee> employees = new()
{
    new Employee { Name = "John", Salary = 50000 },
    new Employee { Name = "David", Salary = 70000 },
    new Employee { Name = "Peter", Salary = 50000 },
    new Employee { Name = "Adam", Salary = 70000 }
};

var sortedEmployees = employees
    .OrderByDescending(e => e.Salary)
    .ThenBy(e => e.Name);

foreach (var employee in sortedEmployees)
{
    Console.WriteLine($"{employee.Name}: {employee.Salary}");
}

class Employee
{
    public string Name { get; set; } = "";
    public decimal Salary { get; set; }
}

Output:

Adam: 70000
David: 70000
John: 50000
Peter: 50000

Diagram

Employees
    |
    v
OrderByDescending(Salary)
    |
    v
70000 -> Adam, David
50000 -> John, Peter
    |
    v
ThenBy(Name)
    |
    v
Adam  -> 70000
David -> 70000
John  -> 50000
Peter -> 50000

Key Points

  • OrderBy() sorts ascending.

  • OrderByDescending() sorts descending.

  • ThenBy() performs secondary ascending sorting.

  • ThenByDescending() performs secondary descending sorting.

  • Calling another OrderBy() starts a new primary sort rather than adding a secondary sort.

  • Sorting typically takes O(n log n) time.

 

7. How do you implement a generic repository in ASP.NET Core?

What is a Generic Repository?

A Generic Repository provides reusable data access operations for different entity types.

Instead of writing separate CRUD implementations for every entity, we create a generic interface and implementation.

Architecture Diagram

ASP.NET Core Web API
        |
        v
   Controller
        |
        v
   IGenericRepository<T>
        |
        v
   GenericRepository<T>
        |
        v
    EF Core DbContext
        |
        v
     SQL Server

Step 1: Create Entity

public class Employee
{
    public int Id { get; set; }
    public string Name { get; set; } = "";
    public decimal Salary { get; set; }
}

Step 2: Create DbContext

using Microsoft.EntityFrameworkCore;

public class AppDbContext : DbContext
{
    public AppDbContext(
        DbContextOptions<AppDbContext> options)
        : base(options)
    {
    }

    public DbSet<Employee> Employees => Set<Employee>();
}

Step 3: Create Generic Repository Interface

public interface IGenericRepository<T> where T : class
{
    Task<T?> GetByIdAsync(int id);

    Task<List<T>> GetAllAsync();

    Task AddAsync(T entity);

    void Update(T entity);

    void Delete(T entity);

    Task SaveChangesAsync();
}

Step 4: Implement Generic Repository

using Microsoft.EntityFrameworkCore;

public class GenericRepository<T> : IGenericRepository<T>
    where T : class
{
    private readonly AppDbContext _context;
    private readonly DbSet<T> _dbSet;

    public GenericRepository(AppDbContext context)
    {
        _context = context;
        _dbSet = context.Set<T>();
    }

    public async Task<T?> GetByIdAsync(int id)
    {
        return await _dbSet.FindAsync(id);
    }

    public async Task<List<T>> GetAllAsync()
    {
        return await _dbSet.ToListAsync();
    }

    public async Task AddAsync(T entity)
    {
        await _dbSet.AddAsync(entity);
    }

    public void Update(T entity)
    {
        _dbSet.Update(entity);
    }

    public void Delete(T entity)
    {
        _dbSet.Remove(entity);
    }

    public async Task SaveChangesAsync()
    {
        await _context.SaveChangesAsync();
    }
}

Step 5: Register Dependencies in Program.cs

builder.Services.AddDbContext<AppDbContext>(options =>
    options.UseSqlServer(
        builder.Configuration.GetConnectionString("DefaultConnection")));

builder.Services.AddScoped(
    typeof(IGenericRepository<>),
    typeof(GenericRepository<>));

Step 6: Use Repository in Controller

using Microsoft.AspNetCore.Mvc;

[ApiController]
[Route("api/[controller]")]
public class EmployeesController : ControllerBase
{
    private readonly IGenericRepository<Employee> _repository;

    public EmployeesController(
        IGenericRepository<Employee> repository)
    {
        _repository = repository;
    }

    [HttpGet]
    public async Task<IActionResult> GetAll()
    {
        var employees = await _repository.GetAllAsync();

        return Ok(employees);
    }

    [HttpPost]
    public async Task<IActionResult> Create(Employee employee)
    {
        await _repository.AddAsync(employee);

        await _repository.SaveChangesAsync();

        return Ok(employee);
    }
}

Example API Response

GET /api/employees

[
  {
    "id": 1,
    "name": "John",
    "salary": 50000
  },
  {
    "id": 2,
    "name": "David",
    "salary": 70000
  }
]

Explanation

  1. Controller depends on IGenericRepository<Employee>.

  2. Dependency Injection provides GenericRepository<Employee>.

  3. Repository uses EF Core to access SQL Server.

  4. SaveChangesAsync() persists changes.

Key Points

  • Generic repositories reduce repeated CRUD code.

  • where T : class restricts the generic type to reference types.

  • DbSet<T> represents the entity set.

  • Use scoped lifetime for EF Core repositories.

  • A generic repository is not always necessary because EF Core already implements Repository and Unit of Work concepts.

  • For production applications, add pagination, validation, cancellation tokens, error handling, and transaction management.

  • In Clean Architecture, repository interfaces usually belong in the Application layer, while EF Core implementations belong in Infrastructure.

 

8. Which collection would you use for caching user details by UserId?

Explanation

For caching user details by UserId, use a Dictionary when access is single-threaded or externally synchronized.

For concurrent applications, use ConcurrentDictionary<TKey, TValue>.

Example Program

using System;
using System.Collections.Generic;

Dictionary<int, string> userCache = new()
{
    { 101, "John" },
    { 102, "David" },
    { 103, "Peter" }
};

if (userCache.TryGetValue(102, out string? userName))
{
    Console.WriteLine(userName);
}

Output:

David

Diagram

Request UserId = 102
        |
        v
Dictionary<int, string>
        |
        v
Lookup Key 102
        |
        v
Return "David"

Explanation

  • UserId is the dictionary key.

  • User details are stored as the value.

  • TryGetValue() retrieves the value safely.

  • Average lookup complexity is O(1).

Real-Time Scenario

In ASP.NET Core, user information may be cached to avoid repeated SQL Server queries.

Web API Request
       |
       v
Check User Cache
       |
       +---- Found ----> Return Cached User
       |
       +---- Missing
                |
                v
           SQL Server
                |
                v
           Cache Result
                |
                v
           Return User

Key Points

  • Dictionary provides average O(1) lookup.

  • Use ConcurrentDictionary for concurrent access.

  • Use IMemoryCache when expiration and eviction are required.

  • Use Redis for shared caching across multiple application servers.

  • Avoid caching sensitive user data unnecessarily.

 

9. How do you implement a thread-safe in-memory cache?

Explanation

A thread-safe cache allows multiple threads to read and update cached data without corrupting the collection.

ConcurrentDictionary<TKey, TValue> supports thread-safe dictionary operations.

Namespace:

using System.Collections.Concurrent;

Example Program

using System;
using System.Collections.Concurrent;
using System.Threading.Tasks;

ConcurrentDictionary<int, string> cache = new();

Parallel.For(1, 6, id =>
{
    cache.TryAdd(id, $"User{id}");
});

foreach (var item in cache.OrderBy(x => x.Key))
{
    Console.WriteLine($"{item.Key}: {item.Value}");
}

Output:

1: User1
2: User2
3: User3
4: User4
5: User5

Explanation of Code

  • ConcurrentDictionary allows concurrent access.

  • Parallel.For() performs iterations concurrently.

  • TryAdd() adds a value only when its key does not already exist.

  • The final output is sorted because concurrent insertion order is not guaranteed.

Diagram

Thread 1 ----+
             |
Thread 2 ----+
             |
Thread 3 ----+----> ConcurrentDictionary
             |              |
Thread 4 ----+              v
             |       Thread-Safe Operations
Thread 5 ----+              |
                            v
                         Cache Data

ASP.NET Core Example Using IMemoryCache

For production applications, IMemoryCache is often more appropriate because it supports expiration and eviction.

Step 1: Register Memory Cache

builder.Services.AddMemoryCache();

Step 2: Create Cache Service

using Microsoft.Extensions.Caching.Memory;

public class UserCacheService
{
    private readonly IMemoryCache _cache;

    public UserCacheService(IMemoryCache cache)
    {
        _cache = cache;
    }

    public string GetUser(int userId)
    {
        return _cache.GetOrCreate(
            $"user_{userId}",
            entry =>
            {
                entry.AbsoluteExpirationRelativeToNow =
                    TimeSpan.FromMinutes(10);

                return $"User{userId}";
            })!;
    }
}

Step 3: Register Service

builder.Services.AddScoped<UserCacheService>();

Explanation

  • IMemoryCache supports concurrent cache access.

  • Cached entries expire after 10 minutes.

  • Expired entries can be removed and recreated.

  • The cache is local to the application instance.

Important: GetOrCreate() does not guarantee that the factory executes only once for concurrent cache misses. Multiple requests may execute the factory simultaneously. Use explicit synchronization or a single-flight mechanism when duplicate loading must be prevented.

Key Points

  • ConcurrentDictionary is suitable for thread-safe key-value storage.

  • IMemoryCache supports expiration and eviction.

  • Thread-safe dictionary operations do not automatically make multi-step workflows atomic.

  • GetOrAdd() factories can execute multiple times concurrently.

  • Use Redis or another distributed cache when multiple servers must share cached data.

  • Cache invalidation is important when underlying data changes.

 

10. How do you convert a list of objects into a Dictionary?

Explanation

Use LINQ ToDictionary() to convert a list of objects into key-value pairs.

For example, convert employees into a dictionary where:

  • Key = Employee ID

  • Value = Employee object

Example Program

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

List<Employee> employees = new()
{
    new Employee { Id = 101, Name = "John" },
    new Employee { Id = 102, Name = "David" },
    new Employee { Id = 103, Name = "Peter" }
};

Dictionary<int, Employee> employeeDict =
    employees.ToDictionary(e => e.Id);

foreach (var item in employeeDict)
{
    Console.WriteLine($"{item.Key}: {item.Value.Name}");
}

class Employee
{
    public int Id { get; set; }
    public string Name { get; set; } = "";
}

Output:

101: John
102: David
103: Peter

Diagram

List<Employee>
      |
      v
  ToDictionary()
      |
      v
Dictionary<int, Employee>
      |
      +---- 101 -> John
      |
      +---- 102 -> David
      |
      +---- 103 -> Peter

Explanation of Code

employees.ToDictionary(e => e.Id);
  • Uses Id as the dictionary key.

  • Stores the entire Employee object as the value.

  • Keys must be unique.

Alternative: Store Only Employee Name

Dictionary<int, string> employeeDict =
    employees.ToDictionary(
        e => e.Id,
        e => e.Name);

Handling Duplicate Keys

ToDictionary() throws an ArgumentException if duplicate keys are found.

If duplicate employee IDs are possible and you want to keep the first employee:

var employeeDict = employees
    .GroupBy(e => e.Id)
    .ToDictionary(
        g => g.Key,
        g => g.First());

This explicitly chooses the first employee for each ID. In business applications, duplicate keys may indicate invalid data, so validate them rather than silently discarding records unless that behavior is intended.

Key Points

  • ToDictionary() converts a sequence into a dictionary.

  • A key selector is required.

  • A value selector is optional.

  • Duplicate keys cause an exception.

  • Average conversion complexity is O(n).

  • Dictionary lookup is O(1) on average.

 

Final Summary: Important Methods and Concepts

Question

Recommended Approach

Important Method

Remove duplicates

LINQ / HashSet

Distinct()

Second-highest number

LINQ sorting

Distinct().OrderByDescending().Skip()

Count word frequency

Dictionary

ContainsKey()

Find duplicates

LINQ grouping

GroupBy()

Group employees

LINQ

GroupBy()

Sort employees

LINQ

OrderByDescending().ThenBy()

Generic Repository

Generics + EF Core

IGenericRepository<T>

Cache by UserId

Dictionary / Cache

TryGetValue()

Thread-safe cache

ConcurrentDictionary / IMemoryCache

TryAdd(), GetOrCreate()

List to Dictionary

LINQ

ToDictionary()

Most Important Interview Takeaways

Q1. Which LINQ methods are most important for collection coding interviews?

Where(), Select(), GroupBy(), OrderBy(), ThenBy(), Distinct(), Any(), FirstOrDefault(), and ToDictionary().

Q2. Which collection is best for removing duplicates?

HashSet<T> or LINQ Distinct().

Q3. Which collection is best for caching user details?

ConcurrentDictionary<TKey,TValue> for simple concurrent key-value storage, IMemoryCache for local caching with expiration, and Redis for distributed caching.

Q4. What is the difference between GroupBy() and ToDictionary()?

GroupBy() creates groups of elements sharing a key. ToDictionary() creates a key-value lookup and requires unique keys.

Q5. Is Generic Repository mandatory in ASP.NET Core?

No. EF Core already provides repository-like functionality. A custom generic repository is useful when it provides meaningful abstraction or reusable application-specific behavior.

Q6. What are the most important real-time coding scenarios for a .NET developer?

Focus on removing duplicates, finding the second-highest value, counting frequencies, grouping and sorting records, dictionary lookups, and implementing caching with correct concurrency handling.

← Back to Articles