PYnative

Python Programming

  • Learn Python ▼
    • Python Tutorials
    • Python Basics
    • Python Interview Q&As
  • Exercises ▼
    • Python Exercises
    • C++ Exercises
    • C Programming Exercises
    • Java Exercises
    • C# Exercises
  • Quizzes
  • Code Editor ▼
    • Online Python Code Editor
    • Online C Compiler
    • Online C++ Compiler
    • Online Java Compiler
    • Online C# Compiler
Home » C# Exercises » C# Extension Methods Exercises: 20 Coding Problems with Solutions

C# Extension Methods Exercises: 20 Coding Problems with Solutions

Updated on: July 15, 2026 | Leave a Comment

Extension methods let you add new functionality to existing types, including ones you don’t own, without modifying their source code or creating a subclass. This collection of 20 C# extension method exercises walks you through writing your own extensions for built-in types like string, int, and List<T>, a technique widely used throughout LINQ and the .NET framework itself.

Each exercise includes a Practice Problem, Purpose, Hint, and a full Solution with Explanation, so you understand exactly how the this keyword turns a static method into an extension.

Also, See: C# Exercises with  22 topic-wise sets and 620+ practice questions.

What You’ll Practice

  • Fundamentals: Static classes, static methods, and the this parameter modifier.
  • String Extensions: Adding custom string manipulation methods.
  • Collection Extensions: Extending List<T> and other collection types.
  • Real-World Use: Chaining extension methods for readable, fluent code.
+ Table Of Contents (20 Exercises)

Table of contents

  • Exercise 1: Convert a String to PascalCase
  • Exercise 2: Check if a Number Is Even or Odd
  • Exercise 3: Count Words in a Sentence
  • Exercise 4: Format a Decimal as a Percentage
  • Exercise 5: Check if a Date Falls on a Weekend
  • Exercise 6: Truncate a Long String
  • Exercise 7: Check if a Collection Is Empty
  • Exercise 8: Shuffle a Collection Randomly
  • Exercise 9: Remove Duplicate Items from a List
  • Exercise 10: Take Random Elements from a Collection
  • Exercise 11: Calculate Age from a Birthdate
  • Exercise 12: Validate an Email Address
  • Exercise 13: Join a Collection of Strings
  • Exercise 14: Serialize and Deserialize an Object to JSON
  • Exercise 15: Check if a Value Is in a List of Values
  • Exercise 16: Get or Add a Value in a Dictionary
  • Exercise 17: Find the Root Cause of an Exception
  • Exercise 18: Paginate a Queryable Collection
  • Exercise 19: Read a Description Attribute from an Enum
  • Exercise 20: Chain Function Calls with Pipe

Exercise 1: Convert a String to PascalCase

Practice Problem: Write an extension method for string that converts a space-separated or snake_case string into PascalCase.

Purpose: This exercise helps you practice writing a basic extension method using the this keyword on the first parameter, letting you call custom logic as if it were a built-in method on string.

Given Input: text = "hello_world"

Expected Output:

Original = hello_world
Pascal Case = HelloWorld
▼ Hint
  • Declare the method as public static string ToPascalCase(this string input) inside a static class.
  • Replace underscores with spaces first, then split the string on spaces to get individual words.
  • For each word, capitalize the first letter and lowercase the rest, then join the words together with no separator.
▼ Solution & Explanation
using System;

namespace ExtensionMethodExercises
{
    static class StringExtensions
    {
        public static string ToPascalCase(this string input)
        {
            string[] words = input.Replace('_', ' ').Split(' ', StringSplitOptions.RemoveEmptyEntries);
            string result = "";

            foreach (string word in words)
            {
                result += char.ToUpper(word[0]) + word.Substring(1).ToLower();
            }

            return result;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            string text = "hello_world";
            string pascalCase = text.ToPascalCase();

            Console.WriteLine($"Original = {text}");
            Console.WriteLine($"Pascal Case = {pascalCase}");
        }
    }
}Code language: C# (cs)

Explanation:

  • this string input: The this modifier on the first parameter is what turns a regular static method into an extension method callable on any string.
  • input.Replace('_', ' ').Split(' ', ...): Normalizes snake_case input into space separated words so both formats can be handled by the same logic.
  • char.ToUpper(word[0]) + word.Substring(1).ToLower(): Capitalizes only the first character of each word and lowercases the remainder before concatenating.
  • text.ToPascalCase(): Once defined, the extension method is called just like any regular instance method on the string.

Exercise 2: Check if a Number Is Even or Odd

Practice Problem: Create two simple extension methods for int that return a boolean indicating if the number is even or odd.

Purpose: This exercise helps you practice writing extension methods on a value type like int, and shows how one extension method can call another to avoid duplicating logic.

Given Input: number = 4

Expected Output:

Number = 4
Is Even = True
Is Odd = False
▼ Hint
  • Declare both methods as public static bool IsEven(this int number) and public static bool IsOdd(this int number).
  • Implement IsEven() using the modulus operator, then implement IsOdd() by simply negating a call to IsEven().
▼ Solution & Explanation
using System;

namespace ExtensionMethodExercises
{
    static class IntExtensions
    {
        public static bool IsEven(this int number)
        {
            return number % 2 == 0;
        }

        public static bool IsOdd(this int number)
        {
            return !number.IsEven();
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            int number = 4;

            Console.WriteLine($"Number = {number}");
            Console.WriteLine($"Is Even = {number.IsEven()}");
            Console.WriteLine($"Is Odd = {number.IsOdd()}");
        }
    }
}Code language: C# (cs)

Explanation:

  • number % 2 == 0: Checks whether dividing the number by 2 leaves no remainder, which is true only for even numbers.
  • !number.IsEven(): Reuses the IsEven() extension method and simply inverts the result instead of repeating the modulus logic.
  • number.IsEven() and number.IsOdd(): Both extension methods are called directly on the int variable as if they were built-in members.

Exercise 3: Count Words in a Sentence

Practice Problem: Extend the string class to count the number of words in a sentence, ignoring extra spaces.

Purpose: This exercise helps you practice using string.Split() with an option that removes empty entries, so consecutive or leading and trailing spaces do not get counted as extra words.

Given Input: sentence = " Coding is fun "

Expected Output:

Sentence = " Coding is fun "
Word Count = 3
▼ Hint

Call sentence.Split(' ', StringSplitOptions.RemoveEmptyEntries) and return the length of the resulting array.

▼ Solution & Explanation
using System;

namespace ExtensionMethodExercises
{
    static class StringExtensions
    {
        public static int WordCount(this string sentence)
        {
            string[] words = sentence.Split(' ', StringSplitOptions.RemoveEmptyEntries);
            return words.Length;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            string sentence = " Coding is fun ";
            int count = sentence.WordCount();

            Console.WriteLine($"Sentence = \"{sentence}\"");
            Console.WriteLine($"Word Count = {count}");
        }
    }
}Code language: C# (cs)

Explanation:

  • sentence.Split(' ', StringSplitOptions.RemoveEmptyEntries): Splits the sentence on spaces while discarding empty strings caused by extra or leading and trailing spaces.
  • words.Length: Returns the count of actual words remaining after the empty entries have been removed.

Exercise 4: Format a Decimal as a Percentage

Practice Problem: Create a method for double that formats a decimal fraction as a percentage string with a specified number of decimal places.

Purpose: This exercise helps you practice writing an extension method that accepts an additional parameter beyond the instance it extends, similar to how many built-in formatting methods work.

Given Input: fraction = 0.856, decimalPlaces = 1

Expected Output:

Fraction = 0.856
Percentage = 85.6%
▼ Hint
  • Declare the method as public static string ToPercentage(this double value, int decimalPlaces).
  • Multiply the value by 100 first, then format it using a fixed point format string built from decimalPlaces, such as "F" + decimalPlaces.
  • Append a literal % character to the formatted number before returning it.
▼ Solution & Explanation
using System;

namespace ExtensionMethodExercises
{
    static class DoubleExtensions
    {
        public static string ToPercentage(this double value, int decimalPlaces)
        {
            double percentage = value * 100;
            return $"{percentage.ToString("F" + decimalPlaces)}%";
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            double fraction = 0.856;
            string result = fraction.ToPercentage(1);

            Console.WriteLine($"Fraction = {fraction}");
            Console.WriteLine($"Percentage = {result}");
        }
    }
}Code language: C# (cs)

Explanation:

  • this double value, int decimalPlaces: The extension method extends double while still accepting a normal second parameter for how many decimal places to show.
  • value * 100: Converts the decimal fraction into a whole percentage value before formatting.
  • percentage.ToString("F" + decimalPlaces): Builds a dynamic fixed point format string so the number of decimal places can vary per call.

Exercise 5: Check if a Date Falls on a Weekend

Practice Problem: Extend DateTime to check if a given date falls on a Saturday or Sunday.

Purpose: This exercise helps you practice writing an extension method on a built-in struct type like DateTime, and reading its DayOfWeek property to make a decision.

Given Input: date = January 1, 2000

Expected Output:

Date = 2000-01-01 (Saturday)
Is Weekend = True
▼ Hint

Compare date.DayOfWeek against DayOfWeek.Saturday and DayOfWeek.Sunday using the logical OR operator ||.

▼ Solution & Explanation
using System;

namespace ExtensionMethodExercises
{
    static class DateTimeExtensions
    {
        public static bool IsWeekend(this DateTime date)
        {
            return date.DayOfWeek == DayOfWeek.Saturday || date.DayOfWeek == DayOfWeek.Sunday;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            DateTime date = new DateTime(2000, 1, 1);
            bool isWeekend = date.IsWeekend();

            Console.WriteLine($"Date = {date:yyyy-MM-dd} ({date.DayOfWeek})");
            Console.WriteLine($"Is Weekend = {isWeekend}");
        }
    }
}Code language: C# (cs)

Explanation:

  • date.DayOfWeek: A built-in DateTime property that returns an enum value representing the day of the week.
  • date.DayOfWeek == DayOfWeek.Saturday || date.DayOfWeek == DayOfWeek.Sunday: Returns true only when the date lands on one of the two weekend days.
  • {date:yyyy-MM-dd}: Uses a format specifier inside the string interpolation to display the date in a readable format.

Exercise 6: Truncate a Long String

Practice Problem: Write a method for string that cuts off text at a maximum length and appends "..." if it exceeds that length.

Purpose: This exercise helps you practice combining a length check with string.Substring() inside an extension method, a pattern often used for display text in UIs and previews.

Given Input: text = "Long text here", maxLength = 7

Expected Output:

Original = Long text here
Truncated = Long te...
▼ Hint
  • First check if text.Length is already less than or equal to maxLength, and return the text unchanged if so.
  • Otherwise use text.Substring(0, maxLength) and append "..." to the result.
▼ Solution & Explanation
using System;

namespace ExtensionMethodExercises
{
    static class StringExtensions
    {
        public static string Truncate(this string text, int maxLength)
        {
            if (text.Length <= maxLength)
            {
                return text;
            }

            return text.Substring(0, maxLength) + "...";
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            string text = "Long text here";
            string truncated = text.Truncate(7);

            Console.WriteLine($"Original = {text}");
            Console.WriteLine($"Truncated = {truncated}");
        }
    }
}Code language: C# (cs)

Explanation:

  • if (text.Length <= maxLength): Skips truncation entirely and returns the original text when it already fits within the limit.
  • text.Substring(0, maxLength): Extracts only the first maxLength characters from the string.
  • + "...": Appends the ellipsis to signal that the text was cut off.

Exercise 7: Check if a Collection Is Empty

Practice Problem: Write a method to cleanly check if an enumerable is empty, serving as a more readable alternative to !collection.Any().

Purpose: This exercise helps you practice writing a generic extension method on IEnumerable<T>, so the same method works for lists, arrays, and any other sequence type.

Given Input: An empty List<int>.

Expected Output: Is Empty = True

▼ Hint
  • Declare the method as public static bool IsEmpty<T>(this IEnumerable<T> source).
  • Return !source.Any() so the extension method is just a more expressive wrapper around the existing LINQ check.
▼ Solution & Explanation
using System;
using System.Collections.Generic;
using System.Linq;

namespace ExtensionMethodExercises
{
    static class EnumerableExtensions
    {
        public static bool IsEmpty<T>(this IEnumerable<T> source)
        {
            return !source.Any();
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            List<int> numbers = new List<int>();

            Console.WriteLine($"Is Empty = {numbers.IsEmpty()}");
        }
    }
}Code language: C# (cs)

Explanation:

  • IsEmpty<T>(this IEnumerable<T> source): A generic extension method that works on any sequence type, not just List<T>.
  • !source.Any(): Reuses the existing LINQ Any() method and simply inverts it, so callers get a more readable name for the same check.
  • numbers.IsEmpty(): Reads more naturally at the call site than the equivalent !numbers.Any().

Exercise 8: Shuffle a Collection Randomly

Practice Problem: Create an extension method that randomly shuffles the elements of any IEnumerable<T> and returns a new sequence.

Purpose: This exercise helps you practice combining a generic extension method with Random and LINQ’s OrderBy(), a simple way to produce a randomized ordering without writing a manual shuffle algorithm.

Given Input: numbers = { 1, 2, 3, 4, 5 }

Expected Output:

Original = 1, 2, 3, 4, 5
Shuffled = 4, 1, 5, 2, 3

Note: since Shuffle() relies on randomness, the exact order of the shuffled output will differ each time the program runs.

▼ Hint
  • Create a single Random instance and use OrderBy(item => random.Next()) to reorder the sequence unpredictably.
  • Return the result directly from OrderBy() since it already produces a new IEnumerable<T> without modifying the original sequence.
▼ Solution & Explanation
using System;
using System.Collections.Generic;
using System.Linq;

namespace ExtensionMethodExercises
{
    static class EnumerableExtensions
    {
        public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> source)
        {
            Random random = new Random();
            return source.OrderBy(item => random.Next());
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };
            List<int> shuffled = numbers.Shuffle().ToList();

            Console.WriteLine($"Original = {string.Join(", ", numbers)}");
            Console.WriteLine($"Shuffled = {string.Join(", ", shuffled)}");
        }
    }
}Code language: C# (cs)

Explanation:

  • source.OrderBy(item => random.Next()): Assigns each element a random sort key, so the resulting order is effectively randomized.
  • new Random(): Creates a single random number generator that is reused for every element’s sort key within the same call.
  • numbers.Shuffle().ToList(): Calls the extension method and materializes the shuffled sequence into a new list, leaving the original numbers list untouched.

Exercise 9: Remove Duplicate Items from a List

Practice Problem: Extend IList<T> to remove duplicate elements from the collection in-place.

Purpose: This exercise helps you practice writing an extension method that mutates the original collection directly, instead of returning a new sequence like most LINQ style methods do.

Given Input: numbers = { 1, 2, 2, 3, 4, 4, 5 }

Expected Output: After Removing Duplicates = 1, 2, 3, 4, 5

▼ Hint
  • Declare the method as public static void RemoveDuplicates<T>(this IList<T> list) since it modifies the list and does not need to return anything.
  • Use a HashSet<T> to track values already seen, and loop through the list backwards with RemoveAt() so removing an item does not skip the next one.
▼ Solution & Explanation
using System;
using System.Collections.Generic;
using System.Linq;

namespace ExtensionMethodExercises
{
    static class ListExtensions
    {
        public static void RemoveDuplicates<T>(this IList<T> list)
        {
            HashSet<T> seen = new HashSet<T>();

            for (int i = list.Count - 1; i >= 0; i--)
            {
                if (!seen.Add(list[i]))
                {
                    list.RemoveAt(i);
                }
            }
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            List<int> numbers = new List<int> { 1, 2, 2, 3, 4, 4, 5 };
            numbers.RemoveDuplicates();

            Console.WriteLine($"After Removing Duplicates = {string.Join(", ", numbers)}");
        }
    }
}Code language: C# (cs)

Explanation:

  • for (int i = list.Count - 1; i >= 0; i--): Iterates from the end of the list toward the start, so removing an item never shifts the indices still left to check.
  • seen.Add(list[i]): HashSet<T>.Add() returns false when the value already exists in the set, which signals a duplicate.
  • list.RemoveAt(i): Removes the duplicate element directly from the original list, since the method modifies list in-place rather than returning a copy.

Exercise 10: Take Random Elements from a Collection

Practice Problem: Write a method that returns a specified number of random elements from a collection.

Purpose: This exercise helps you practice combining a randomized ordering with LINQ’s Take() method to sample a subset of a collection, useful for things like picking random items to display or test.

Given Input: items = { "Apple", "Banana", "Cherry", "Date", "Elderberry" }, count = 3

Expected Output: Random Items = Cherry, Apple, Elderberry

Note: since TakeRandom() relies on randomness, the exact items and their order will differ each time the program runs.

▼ Hint
  • Reuse the same shuffling idea from Shuffle(), ordering the sequence by a random key with OrderBy(item => random.Next()).
  • Chain .Take(count) after the random ordering to keep only the requested number of elements.
▼ Solution & Explanation
using System;
using System.Collections.Generic;
using System.Linq;

namespace ExtensionMethodExercises
{
    static class EnumerableExtensions
    {
        public static IEnumerable<T> TakeRandom<T>(this IEnumerable<T> source, int count)
        {
            Random random = new Random();
            return source.OrderBy(item => random.Next()).Take(count);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            List<string> items = new List<string> { "Apple", "Banana", "Cherry", "Date", "Elderberry" };
            List<string> randomItems = items.TakeRandom(3).ToList();

            Console.WriteLine($"Random Items = {string.Join(", ", randomItems)}");
        }
    }
}Code language: C# (cs)

Explanation:

  • source.OrderBy(item => random.Next()).Take(count): Randomizes the order of the entire sequence first, then keeps only the first count elements from that shuffled order.
  • this IEnumerable<T> source, int count: The extension method extends any sequence type while accepting a normal parameter for how many random elements to return.
  • items.TakeRandom(3): Calls the extension method to pull three random items out of the five available strings.

Exercise 11: Calculate Age from a Birthdate

Practice Problem: Extend DateTime (representing a birthdate) to accurately calculate a person’s current age in years, accounting for leap years and months.

Purpose: This exercise helps you practice date arithmetic that goes beyond a simple year subtraction, correctly handling cases where the birthday has not yet occurred in the current year.

Given Input: birthDate = July 20, 2000

Expected Output:

Birth Date = 2000-07-20
Age = 25

Note: since Age() is based on DateTime.Today, the output above reflects the current date and will change as time passes.

▼ Hint
  • Start with a simple today.Year - birthDate.Year subtraction to get a rough age.
  • Then check whether the birthday has already occurred this year by comparing birthDate.Date to today.AddYears(-age), and subtract one from the age if it has not.
▼ Solution & Explanation
using System;

namespace ExtensionMethodExercises
{
    static class DateTimeExtensions
    {
        public static int Age(this DateTime birthDate)
        {
            DateTime today = DateTime.Today;
            int age = today.Year - birthDate.Year;

            if (birthDate.Date > today.AddYears(-age))
            {
                age--;
            }

            return age;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            DateTime birthDate = new DateTime(2000, 7, 20);
            int age = birthDate.Age();

            Console.WriteLine($"Birth Date = {birthDate:yyyy-MM-dd}");
            Console.WriteLine($"Age = {age}");
        }
    }
}Code language: C# (cs)

Explanation:

  • today.Year - birthDate.Year: Provides a starting estimate of the age based purely on the difference in calendar years.
  • birthDate.Date > today.AddYears(-age): Checks whether this year’s birthday date has already passed by shifting today back by the estimated age and comparing the two dates directly.
  • age--: Corrects the estimate downward by one year if the birthday later in the year has not happened yet.

Exercise 12: Validate an Email Address

Practice Problem: Create a method that uses Regex to validate whether a string is a properly formatted email address.

Purpose: This exercise helps you practice combining an extension method with System.Text.RegularExpressions to perform pattern based validation on a string.

Given Input: email = "test@test.com"

Expected Output:

Email = test@test.com
Is Valid Email = True
▼ Hint
  • Use a regular expression that requires characters before and after an @ symbol, followed by a dot and more characters.
  • Call Regex.IsMatch(email, pattern) to test the string against the pattern and return a boolean.
▼ Solution & Explanation
using System;
using System.Text.RegularExpressions;

namespace ExtensionMethodExercises
{
    static class StringExtensions
    {
        public static bool IsValidEmail(this string email)
        {
            string pattern = @"^[^@\s]+@[^@\s]+\.[^@\s]+$";
            return Regex.IsMatch(email, pattern);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            string email = "test@test.com";
            bool isValid = email.IsValidEmail();

            Console.WriteLine($"Email = {email}");
            Console.WriteLine($"Is Valid Email = {isValid}");
        }
    }
}Code language: C# (cs)

Explanation:

  • @"^[^@\s]+@[^@\s]+\.[^@\s]+$": A regular expression requiring one or more non-space, non-@ characters, an @ symbol, more such characters, a literal dot, and a final group of characters.
  • Regex.IsMatch(email, pattern): Tests the entire email string against the pattern and returns true only if it matches from start to end.

Exercise 13: Join a Collection of Strings

Practice Problem: Extend IEnumerable<string> to join elements into a single string with a custom separator (shortcut for string.Join).

Purpose: This exercise helps you practice writing a thin extension method wrapper around an existing static method, so the separator focused call reads more naturally at the call site.

Given Input: letters = { "A", "B" }, separator = ", "

Expected Output: Joined = A, B

▼ Hint

Inside the method, simply call and return string.Join(separator, source), passing the extended sequence as the values to join.

▼ Solution & Explanation
using System;
using System.Collections.Generic;
using System.Linq;

namespace ExtensionMethodExercises
{
    static class EnumerableExtensions
    {
        public static string JoinStrings(this IEnumerable<string> source, string separator)
        {
            return string.Join(separator, source);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            string[] letters = { "A", "B" };
            string joined = letters.JoinStrings(", ");

            Console.WriteLine($"Joined = {joined}");
        }
    }
}Code language: C# (cs)

Explanation:

  • this IEnumerable<string> source, string separator: Extends any string sequence while accepting the separator as a normal second parameter.
  • string.Join(separator, source): Delegates the actual joining work to the existing built-in method, keeping the extension method a thin, readable wrapper.
  • letters.JoinStrings(", "): Reads more like a fluent instance call compared to the equivalent string.Join(", ", letters).

Exercise 14: Serialize and Deserialize an Object to JSON

Practice Problem: Create generic extension methods to easily serialize any object to a JSON string and deserialize a JSON string back into an object using System.Text.Json.

Purpose: This exercise helps you practice writing generic extension methods on both a general type T and on string, wrapping System.Text.Json calls behind more convenient names.

Given Input: person = new Person { Name = "Alice", Age = 30 }

Expected Output:

JSON = {"Name":"Alice","Age":30}
Deserialized Name = Alice
Deserialized Age = 30
▼ Hint
  • Declare ToJson<T>(this T obj) and have it return JsonSerializer.Serialize(obj).
  • Declare FromJson<T>(this string json) and have it return JsonSerializer.Deserialize<T>(json).
  • Since FromJson<T> cannot infer T from a plain string, the caller must specify it explicitly, for example json.FromJson<Person>().
▼ Solution & Explanation
using System;
using System.Text.Json;

namespace ExtensionMethodExercises
{
    static class JsonExtensions
    {
        public static string ToJson<T>(this T obj)
        {
            return JsonSerializer.Serialize(obj);
        }

        public static T FromJson<T>(this string json)
        {
            return JsonSerializer.Deserialize<T>(json);
        }
    }

    class Person
    {
        public string Name { get; set; }
        public int Age { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Person person = new Person { Name = "Alice", Age = 30 };

            string json = person.ToJson();
            Person deserializedPerson = json.FromJson<Person>();

            Console.WriteLine($"JSON = {json}");
            Console.WriteLine($"Deserialized Name = {deserializedPerson.Name}");
            Console.WriteLine($"Deserialized Age = {deserializedPerson.Age}");
        }
    }
}Code language: C# (cs)

Explanation:

  • JsonSerializer.Serialize(obj): Converts the object’s public properties into a compact JSON formatted string.
  • JsonSerializer.Deserialize<T>(json): Parses the JSON string back into an instance of the specified type T.
  • json.FromJson<Person>(): Since the string itself carries no type information, the target type must be supplied explicitly as a generic argument.

Exercise 15: Check if a Value Is in a List of Values

Practice Problem: Write a generic extension method In<T> that checks if an item exists within a provided array or list of arguments.

Purpose: This exercise helps you practice writing a generic extension method that uses the params keyword, allowing callers to pass any number of comparison values directly as arguments.

Given Input: myStatus = Status.Pending, checked against Status.Active, Status.Pending

Expected Output:

Status = Pending
Is In List = True
▼ Hint
  • Declare the method as public static bool In<T>(this T item, params T[] values) so it accepts a variable number of comparison values.
  • Use Array.IndexOf(values, item) and check whether the result is 0 or greater to confirm a match.
▼ Solution & Explanation
using System;

namespace ExtensionMethodExercises
{
    enum Status
    {
        Active,
        Pending,
        Closed
    }

    static class ObjectExtensions
    {
        public static bool In<T>(this T item, params T[] values)
        {
            return Array.IndexOf(values, item) >= 0;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Status myStatus = Status.Pending;
            bool isInList = myStatus.In(Status.Active, Status.Pending);

            Console.WriteLine($"Status = {myStatus}");
            Console.WriteLine($"Is In List = {isInList}");
        }
    }
}Code language: C# (cs)

Explanation:

  • params T[] values: Lets the caller pass any number of comparison values as plain arguments instead of building an array manually.
  • Array.IndexOf(values, item): Searches the values array for the item and returns its position, or -1 if it is not found.
  • myStatus.In(Status.Active, Status.Pending): Reads naturally as checking whether the status falls within an inline set of allowed values.

Exercise 16: Get or Add a Value in a Dictionary

Practice Problem: Extend IDictionary so that if a key doesn’t exist, it evaluates a factory function, adds the result to the dictionary, and returns it.

Purpose: This exercise helps you practice combining TryGetValue() with a Func<V> factory parameter, a pattern often used for simple in-memory caching.

Given Input: An empty Dictionary<string, int>, key "count", factory returning 42

Expected Output:

Result = 42
Dictionary Now Contains Key = True
▼ Hint
  • Declare the method as public static V GetOrAdd<K, V>(this IDictionary<K, V> dictionary, K key, Func<V> factory).
  • Use TryGetValue() to check for the key first, only calling the factory and inserting into the dictionary when the key is missing.
▼ Solution & Explanation
using System;
using System.Collections.Generic;

namespace ExtensionMethodExercises
{
    static class DictionaryExtensions
    {
        public static V GetOrAdd<K, V>(this IDictionary<K, V> dictionary, K key, Func<V> factory)
        {
            if (!dictionary.TryGetValue(key, out V value))
            {
                value = factory();
                dictionary[key] = value;
            }

            return value;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Dictionary<string, int> cache = new Dictionary<string, int>();

            int result = cache.GetOrAdd("count", () => 42);

            Console.WriteLine($"Result = {result}");
            Console.WriteLine($"Dictionary Now Contains Key = {cache.ContainsKey("count")}");
        }
    }
}Code language: C# (cs)

Explanation:

  • dictionary.TryGetValue(key, out V value): Checks for the key without throwing an exception, and captures the existing value if one is found.
  • value = factory(): Only runs the factory function when the key was missing, avoiding unnecessary work when the value already exists.
  • cache.GetOrAdd("count", () => 42): Passes a lambda as the factory, which is only invoked the first time the key is requested.

Exercise 17: Find the Root Cause of an Exception

Practice Problem: Write a method that recursively traverses an Exception‘s InnerException property to find and return the root cause exception.

Purpose: This exercise helps you practice writing an extension method that walks a chain of linked objects, a pattern that shows up whenever exceptions are wrapped by multiple layers of application code.

Given Input: A chain of three exceptions, where the outer exception wraps a middle exception that wraps a root cause exception.

Expected Output: Innermost Message = Root cause failure

▼ Hint
  • Use a while loop that keeps moving to current.InnerException as long as it is not null.
  • Return current once the loop ends, since at that point it holds the exception with no further inner exception.
▼ Solution & Explanation
using System;

namespace ExtensionMethodExercises
{
    static class ExceptionExtensions
    {
        public static Exception GetInnermostException(this Exception exception)
        {
            Exception current = exception;

            while (current.InnerException != null)
            {
                current = current.InnerException;
            }

            return current;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Exception rootCause = new InvalidOperationException("Root cause failure");
            Exception middleException = new ApplicationException("Middle layer error", rootCause);
            Exception topException = new Exception("Top level error", middleException);

            Exception innermost = topException.GetInnermostException();

            Console.WriteLine($"Innermost Message = {innermost.Message}");
        }
    }
}Code language: C# (cs)

Explanation:

  • while (current.InnerException != null): Keeps descending through the chain of wrapped exceptions until reaching one with no inner exception.
  • current = current.InnerException: Moves the traversal one level deeper on each iteration of the loop.
  • topException.GetInnermostException(): Called on the outermost exception, but returns the original root cause buried at the bottom of the chain.

Exercise 18: Paginate a Queryable Collection

Practice Problem: Create a pagination extension method for IQueryable<T> that takes a pageNumber and pageSize and applies the correct .Skip() and .Take() logic.

Purpose: This exercise helps you practice writing an extension method on IQueryable<T>, so the same pagination logic can later be pushed down to a database query instead of only working on in-memory collections.

Given Input: Numbers 1 through 20, pageNumber = 2, pageSize = 5

Expected Output: Page 2 (Page Size 5) = 6, 7, 8, 9, 10

▼ Hint
  • Calculate how many items to skip using (pageNumber - 1) * pageSize, then chain .Take(pageSize) after the skip.
  • Both .Skip() and .Take() work directly on IQueryable<T>, so no conversion to a list is needed inside the extension method itself.
▼ Solution & Explanation
using System;
using System.Collections.Generic;
using System.Linq;

namespace ExtensionMethodExercises
{
    static class QueryableExtensions
    {
        public static IQueryable<T> Page<T>(this IQueryable<T> source, int pageNumber, int pageSize)
        {
            return source.Skip((pageNumber - 1) * pageSize).Take(pageSize);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            IQueryable<int> numbers = Enumerable.Range(1, 20).AsQueryable();

            List<int> secondPage = numbers.Page(2, 5).ToList();

            Console.WriteLine($"Page 2 (Page Size 5) = {string.Join(", ", secondPage)}");
        }
    }
}Code language: C# (cs)

Explanation:

  • (pageNumber - 1) * pageSize: Converts a 1 based page number into the number of items that need to be skipped to reach that page.
  • source.Skip(...).Take(pageSize): Skips past all earlier pages, then takes only enough items to fill the current page.
  • numbers.Page(2, 5): Requests the second page of results using a page size of five items each.

Exercise 19: Read a Description Attribute from an Enum

Practice Problem: Write an extension method for enums that reads and returns the string value from a [Description] attribute decorated on the enum member.

Purpose: This exercise helps you practice using reflection inside an extension method to read a custom attribute applied to a specific enum member, a common technique for showing friendly labels in a UI.

Given Input: status = OrderStatus.Shipped

Expected Output:

Status = Shipped
Description = Order Shipped
▼ Hint
  • Decorate each enum member with [Description("...")] from the System.ComponentModel namespace.
  • Use value.GetType().GetField(value.ToString()) to get the reflection info for the specific enum member.
  • Call GetCustomAttribute<DescriptionAttribute>() on that field, and fall back to value.ToString() if no attribute is present.
▼ Solution & Explanation
using System;
using System.ComponentModel;
using System.Reflection;

namespace ExtensionMethodExercises
{
    enum OrderStatus
    {
        [Description("Order Placed")]
        Placed,

        [Description("Order Shipped")]
        Shipped,

        [Description("Order Delivered")]
        Delivered
    }

    static class EnumExtensions
    {
        public static string GetDescription(this Enum value)
        {
            FieldInfo field = value.GetType().GetField(value.ToString());
            DescriptionAttribute attribute = field.GetCustomAttribute<DescriptionAttribute>();

            return attribute != null ? attribute.Description : value.ToString();
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            OrderStatus status = OrderStatus.Shipped;
            string description = status.GetDescription();

            Console.WriteLine($"Status = {status}");
            Console.WriteLine($"Description = {description}");
        }
    }
}Code language: C# (cs)

Explanation:

  • value.GetType().GetField(value.ToString()): Uses reflection to locate the specific field on the enum type that matches the current member’s name.
  • field.GetCustomAttribute<DescriptionAttribute>(): Reads the Description attribute applied to that field, returning null if it was never added.
  • attribute != null ? attribute.Description : value.ToString(): Falls back to the raw enum name whenever a member has no description attribute defined.

Exercise 20: Chain Function Calls with Pipe

Practice Problem: Create a functional programming-style Pipe extension method that allows you to pass the object as an argument into a sequence of functions smoothly.

Purpose: This exercise helps you practice writing a generic extension method with two type parameters, enabling a fluent left to right chain of transformations instead of nested function calls.

Given Input: 5.Pipe(x => x * 2).Pipe(x => x.ToString())

Expected Output: Result = 10

▼ Hint
  • Declare the method as public static TResult Pipe<T, TResult>(this T input, Func<T, TResult> function).
  • Inside the body, simply call and return function(input), letting the caller supply whatever transformation is needed.
  • Since Pipe() itself returns the transformed result, calls can be chained one after another, each feeding into the next.
▼ Solution & Explanation
using System;

namespace ExtensionMethodExercises
{
    static class ObjectExtensions
    {
        public static TResult Pipe<T, TResult>(this T input, Func<T, TResult> function)
        {
            return function(input);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            string result = 5.Pipe(x => x * 2).Pipe(x => x.ToString());

            Console.WriteLine($"Result = {result}");
        }
    }
}Code language: C# (cs)

Explanation:

  • Pipe<T, TResult>(this T input, Func<T, TResult> function): Extends any type T and applies a function that transforms it into a possibly different type TResult.
  • 5.Pipe(x => x * 2): Passes the integer 5 into the first lambda, producing the integer 10.
  • .Pipe(x => x.ToString()): Chains a second call directly onto the result of the first, converting the integer 10 into the string “10”.

Filed Under: C# Exercises

Did you find this page helpful? Let others know about it. Sharing helps me continue to create free Python resources.

TweetF  sharein  shareP  Pin

About Vishal

I’m Vishal Hule, the Founder of PYnative.com. As a Python developer, I enjoy assisting students, developers, and learners. Follow me on Twitter.

Related Tutorial Topics:

C# Exercises

All Coding Exercises:

C Exercises
C++ Exercises
Python Exercises
Java Exercises
C# Exercises

Python Exercises and Quizzes

Free coding exercises and quizzes cover Python basics, data structure, data analytics, and more.

  • 15+ Topic-specific Exercises and Quizzes
  • Each Exercise contains 25+ questions
  • Each Quiz contains 25 MCQ
Exercises
Quizzes

Leave a Reply Cancel reply

your email address will NOT be published. all comments are moderated according to our comment policy.

Use <pre> tag for posting code. E.g. <pre> Your entire code </pre>

In: C# Exercises
TweetF  sharein  shareP  Pin

  C# Exercises

  • C# Exercise for Beginners
  • C# Loops Exercise
  • C# Array Exercise
  • C# String Exercise
  • C# OOP Exercise
  • C# Structs, Records and Enums Exercise
  • C# Collections Exercise
  • C# List Exercise
  • C# Dictionary Exercise
  • C# LINQ Exercise
  • C# Exception Handling Exercise
  • C# File Handling Exercise
  • C# Date and Time Exercise
  • C# Generics Exercise
  • C# Lambda Expressions Exercise
  • C# Delegates and Events Exercise
  • C# Extension Methods Exercise
  • C# Regex Exercise
  • C# Pattern Matching Exercise
  • C# Iterators and Yield Exercise
  • C# Indexers and Operator Overloading Exercise
  • C# Random Data Generation Exercise

All Coding Exercises

Python Exercises C Exercises C++ Exercises Java Exercises C# Exercises

About PYnative

PYnative.com is for Python lovers. Here, You can get Tutorials, Exercises, and Quizzes to practice and improve your Python skills.

Follow Us

To get New Python Tutorials, Exercises, and Quizzes

  • Twitter
  • Facebook
  • Sitemap

Explore Python

  • Learn Python
  • Python Basics
  • Python Databases
  • Python Exercises
  • Python Quizzes
  • Online Python Code Editor
  • Python Tricks

Coding Exercises

  • C Exercises
  • C++ Exercises
  • Python Exercises
  • Java Exercises
  • C# Exercises

Legal Stuff

  • About Us
  • Contact Us

We use cookies to improve your experience. While using PYnative, you agree to have read and accepted our:

  • Terms Of Use
  • Privacy Policy
  • Cookie Policy

Copyright © 2018–2026 pynative.com