So I know that Find() is only a List method, whereas First() is an extension for any IEnumerable. I als
First will throw an exception when it finds nothing, FirstOrDefault however does exactly the same as Find (apart from how it iterates through the elements).
1- Find() returns Null if the entity is not in the context but First() will throw an exception
2- Find() returns entities that have been added to the context but have not yet been saved to the database
BTW Find is rather equal to FirstOrDefault() than to First(). Because if predicate of First() is not satisfied with any list elements you will get an exception.
Here what returns a dotpeek, another great free reflector replacement with some of ReSharper features
Here for Enumerable.First(...) and Enumerable.FirstOrDefault(...) extension methods:
public static TSource FirstOrDefault<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) {
if (source == null) throw Error.ArgumentNull("source");
if (predicate == null) throw Error.ArgumentNull("predicate");
foreach (TSource element in source) {
if (predicate(element)) return element;
}
return default(TSource);
}
public static TSource First<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) {
if (source == null) throw Error.ArgumentNull("source");
if (predicate == null) throw Error.ArgumentNull("predicate");
foreach (TSource element in source) {
if (predicate(element)) return element;
}
throw Error.NoMatch();
}
and here is for List<>.Find:
/// <summary>
/// Searches for an element that matches the conditions defined by the specified predicate, and returns the first occurrence within the entire <see cref="T:System.Collections.Generic.List`1"/>.
/// </summary>
///
/// <returns>
/// The first element that matches the conditions defined by the specified predicate, if found; otherwise, the default value for type <paramref name="T"/>.
/// </returns>
/// <param name="match">The <see cref="T:System.Predicate`1"/> delegate that defines the conditions of the element to search for.</param><exception cref="T:System.ArgumentNullException"><paramref name="match"/> is null.</exception>
[__DynamicallyInvokable]
public T Find(Predicate<T> match)
{
if (match == null)
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match);
for (int index = 0; index < this._size; ++index)
{
if (match(this._items[index]))
return this._items[index];
}
return default (T);
}
Here's the code for List<T>.Find (from Reflector):
public T Find(Predicate<T> match)
{
if (match == null)
{
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match);
}
for (int i = 0; i < this._size; i++)
{
if (match(this._items[i]))
{
return this._items[i];
}
}
return default(T);
}
And here's Enumerable.First:
public static TSource First<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
if (source == null)
{
throw Error.ArgumentNull("source");
}
if (predicate == null)
{
throw Error.ArgumentNull("predicate");
}
foreach (TSource local in source)
{
if (predicate(local))
{
return local;
}
}
throw Error.NoMatch();
}
So both methods work roughly the same way: they iterate all items until they find one that matches the predicate. The only noticeable difference is that Find uses a for loop because it already knows the number of elements, and First uses a foreach loop because it doesn't know it.
Since List<> is not indexed in any way, it has to go through all values to find a specific value. Therefore it doesn't make much of a difference compared to traversing the list via an enumerable (apart from the creation of a enumerable helper object instance).
That said, keep in mind that the Find function was created way earlier than the First extension method (Framework V2.0 vs. V3.5), and I doubt that they would have implemented Find if the List<> class had been implemented at the same time as the extension methods.