Click here to Skip to main content
Click here to Skip to main content

Using Find in a Generic List

, 27 Oct 2008
Rate this:
Please Sign up or sign in to vote.
This article investigates the use of List.Find() when using value and reference types, and how to use it when working with your own custom classes.

GenericsFind

Introduction

There're quite a few ways to find an object inside a Generic List, but we'll focus on one specific method List<T>.Find(), and investigate its behavior when working with value types and reference types.

Background

While working with Generics the other day, I stumbled on a few things that are important to keep in mind when using the Find() method on a generic list. Especially when working with value types, and your search criteria is literally the default value returned when no results were found. I ended up discovering a few things about Find() and how to use it on your own custom classes. There's also a simple helper method that takes in an array of custom types and checks if the specified object was found.

I hope this helps someone understand a bit better on what's going on when using the Find() method on a Generic List.

More about List<T>.Find()

List<T>.Find Method - Searches for an element that matches the conditions defined by the specified predicate, and returns the first occurrence within the entire List<T>.

A simple example is a generic list consisting of integers:

List<int> intList1 = new List<int>(new int[] {1,2,3,4});

int intResult = intList1.Find
(
    delegate(int intpar1){return intpar1 == 3}
);

which would basically return the integer if it was found in the list.

However, consider the response when the integer wasn't found:

Extract from MSDN help:

When searching a list containing value types, make sure the default value for the type does not satisfy the search predicate. Otherwise, there is no way to distinguish between a default value indicating that no match was found and a list element that happens to have the default value for the type. If the default value satisfies the search predicate, use the FindIndex method instead.

So, be careful when using .Find() when your search criteria is literally the default value for the type. (This is especially relevant when using value types.)

One way of handling this is to turn your value types into nullable types. That way, you can avoid 0 being returned when your integer wasn't found in the list:

List<Nullable<int>> intListTemp2 = new List<int?>
(
    new int?[] { 1, 2, 3, 4 }
);    
    
int? intFoundAnon = intListTemp2.Find
(
    delegate(int? intInput1){return intInput1 == 5;}
);

Instead of 0, null is returned if the value wasn't found in the list of value types.

This can be very useful when working with database null values being used in columns that have types such as int or DateTime.

There's another thing to keep in mind when searching for a reference type inside a list:

Reference equality vs. value equality

Value equality is the generally understood meaning of equality: it means that two objects contain the same values. For example, two integers with the value of 2 have value equality.

Reference equality means that there are not two objects to compare. Instead, there are two object references, and both of them refer to the same object.

When you are doing a .Find() on a value type (such as int, bool, char, DateTime, enum, Decimal, ..), the elements are compared based on the value itself. But, if you do a .Find() on a reference type (like a custom class), you'd be looking for objects that have the same reference.

To explain it more: even if you compare two objects with the same values for all properties, it won't necessarily return true.

Patient patTemp1 = new Patient("John");
Patient patTemp2 = new Patient("John"); 

// this will return false
bool blResult = patTemp1.Equals(patTemp2);

Instead, you should make sure your custom class overrides the Equals() method and define how the two objects should be compared.

class Patient : IComparable
public override bool Equals(object obj)
{
    return this.Firstname == ((Patient) obj).Firstname;
}

And, remember to make sure your custom class inherits from the interface "IComparable" as well.

If you remember to do that, you can do a Find() on your Generic List and it will play along as expected (won't return false every time).

List<Patient> PatientList = new List<Patient>
(
    new Patient[] 
    { 
        new Patient("John Smith"), new Patient("Victor Matfield")  
    }
); 

bool blresult = PatientList.Exists
(
    delegate(Patient pTempSearch) 
    {
        return pTempSearch.Equals(new Patient("John Smith"));  
    }
);

The following helper method takes in an array of custom types and checks if the specified object was found.

public bool ArrayContains<T>(T[] array, T value) 
{ 
    return array != null && 
    Array.Exists(array, delegate(T tTemp) 
    {
        return tTemp.Equals(value);
    });
} 

bool blResult = ArrayContains<Patient>(PatientArray, Patient1);

Points of Interest

The code example included covers everything in a bit more depth. If you're like me, looking at the actual code will give some additional insight.

Also, note the use of Nullable Types when using Find() on value types such as Int32.

History

This is the first post and release.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

johan_vw
Software Developer (Senior)
South Africa South Africa
I'm a senior software developer from South Africa and have a huge passion for .NET and Microsoft related technologies.

When I'm not having fun figuring out an architecture or class design, you'd probably find me rocking on the drums, running around with my badminton racquet or enjoying another bitter coffee or an ice-cold Amstel at the bar.

Comments and Discussions

 
GeneralThe IEquatable Interface versus bool Equals(obj) PinmemberMartin.Holzherr30-Oct-08 0:50 
GeneralRe: The IEquatable Interface versus bool Equals(obj) Pinmemberjohan_vw30-Oct-08 3:43 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web01 | 2.8.140827.1 | Last Updated 28 Oct 2008
Article Copyright 2008 by johan_vw
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid