C# > Advanced C# > Collections and Generics > Generic Methods and Classes
Generic Method for Finding an Item in a Collection
This code snippet demonstrates a generic method that can find an item within any collection of a specified type using a predicate. It showcases the power of generics to write reusable and type-safe code.
Code Snippet
The FindItem
method is an extension method for IEnumerable
. This means it can be called on any collection that implements the IEnumerable
interface (e.g., lists, arrays, sets). The method takes a Predicate
as an argument. A Predicate
is a delegate that represents a method that takes an object of type T
and returns a boolean value. The method iterates through the collection and applies the predicate to each item. If the predicate returns true
for an item, the method returns that item. If no item matches the predicate, the method returns default(T)
, which is null
for reference types and the default value (e.g., 0 for int
, false
for bool
) for value types. The example usage shows how to find the first even number in a list of integers and the first name starting with 'C' in a list of strings.
using System;
using System.Collections.Generic;
using System.Linq;
public static class CollectionExtensions
{
public static T FindItem<T>(this IEnumerable<T> collection, Predicate<T> match)
{
foreach (T item in collection)
{
if (match(item))
{
return item;
}
}
return default(T); // Returns null for reference types, default(value) for value types
}
}
// Usage Example:
public class Example
{
public static void Main(string[] args)
{
List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
// Find the first even number in the list
int evenNumber = numbers.FindItem(number => number % 2 == 0);
Console.WriteLine($"The first even number is: {evenNumber}"); // Output: The first even number is: 2
List<string> names = new List<string> { "Alice", "Bob", "Charlie", "David" };
// Find a name that starts with 'C'
string nameStartingWithC = names.FindItem(name => name.StartsWith("C"));
Console.WriteLine($"The first name starting with 'C' is: {nameStartingWithC}"); // Output: The first name starting with 'C' is: Charlie
}
}
Concepts Behind the Snippet
This snippet uses several key concepts:
Real-Life Use Case
Imagine you have a large collection of Another example could be in a game development scenario, where you have a list of game objects and you need to find the first enemy within a certain range:Product
objects and you need to find the first product with a specific price. You could use this generic method to easily find the product:Product foundProduct = productList.FindItem(product => product.Price == 99.99);
GameObject enemyInRange = enemyList.FindItem(enemy => Vector3.Distance(player.transform.position, enemy.transform.position) < 10);
Best Practices
T
is a reference type, be mindful of potential NullReferenceException
if the predicate tries to access members of a null
object.
Interview Tip
Be prepared to discuss the benefits of generics, the purpose of extension methods, and the use of delegates like Predicate
. Also, understand the time complexity of the FindItem
method (O(n) in the worst case).
When to Use Them
Use generic methods when you need to write code that can operate on different types without code duplication. They are particularly useful for algorithms and data structures that are type-agnostic. Extension methods are ideal for adding functionality to existing types without modifying their source code.
Memory Footprint
Generic methods themselves don't inherently increase memory footprint. However, each instantiation of a generic type with a specific type parameter creates a new type, which can contribute to code bloat if many different types are used. The memory footprint of the collection depends on the number of elements it contains and the size of each element.
Alternatives
FirstOrDefault
: LINQ provides a similar method called FirstOrDefault
, which also returns the first element that satisfies a condition. The advantage of using LINQ is that it is more concise and expressive.foreach
Loop: You can always use a standard foreach
loop to iterate through the collection and find the desired element. However, this approach is less reusable and less expressive than using a generic method.
Pros
Cons
FAQ
-
What happens if no item matches the predicate?
The method returnsdefault(T)
, which isnull
for reference types and the default value (e.g., 0 forint
,false
forbool
) for value types. -
Can I use this method with arrays?
Yes, because arrays implement theIEnumerable
interface. -
How is this different from LINQ's `FirstOrDefault`?
FirstOrDefault
is a LINQ method that provides similar functionality. It might be more concise in some cases, but this custom method provides a clear illustration of how generics and predicates work.