| File: System\Linq\Last.cs | Web Access |
| Project: src\runtime\src\libraries\System.Linq\src\System.Linq.csproj (System.Linq) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; namespace System.Linq { public static partial class Enumerable { public static TSource Last<TSource>(this IEnumerable<TSource> source) { TSource? last = source.TryGetLast(out bool found); if (!found) { ThrowHelper.ThrowNoElementsException(); } return last!; } public static TSource Last<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) { TSource? last = source.TryGetLast(predicate, out bool found); if (!found) { ThrowHelper.ThrowNoMatchException(); } return last!; } public static TSource? LastOrDefault<TSource>(this IEnumerable<TSource> source) => source.TryGetLast(out _); /// <summary>Returns the last element of a sequence, or a default value if the sequence contains no elements.</summary> /// <typeparam name="TSource">The type of the elements of <paramref name="source" />.</typeparam> /// <param name="source">An <see cref="IEnumerable{T}" /> to return the last element of.</param> /// <param name="defaultValue">The default value to return if the sequence is empty.</param> /// <returns><paramref name="defaultValue" /> if the source sequence is empty; otherwise, the last element in the <see cref="IEnumerable{T}" />.</returns> /// <exception cref="ArgumentNullException"><paramref name="source" /> is <see langword="null" />.</exception> public static TSource LastOrDefault<TSource>(this IEnumerable<TSource> source, TSource defaultValue) { TSource? last = source.TryGetLast(out bool found); return found ? last! : defaultValue; } public static TSource? LastOrDefault<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) => source.TryGetLast(predicate, out _); /// <summary>Returns the last element of a sequence that satisfies a condition or a default value if no such element is found.</summary> /// <typeparam name="TSource">The type of the elements of <paramref name="source" />.</typeparam> /// <param name="source">An <see cref="IEnumerable{T}" /> to return an element from.</param> /// <param name="predicate">A function to test each element for a condition.</param> /// <param name="defaultValue">The default value to return if the sequence is empty.</param> /// <returns><paramref name="defaultValue" /> if the sequence is empty or if no elements pass the test in the predicate function; otherwise, the last element that passes the test in the predicate function.</returns> /// <exception cref="ArgumentNullException"><paramref name="source" /> or <paramref name="predicate" /> is <see langword="null" />.</exception> public static TSource LastOrDefault<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate, TSource defaultValue) { TSource? last = source.TryGetLast(predicate, out bool found); return found ? last! : defaultValue; } private static TSource? TryGetLast<TSource>(this IEnumerable<TSource> source, out bool found) { if (source is null) { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source); } return source is Iterator<TSource> iterator ? iterator.TryGetLast(out found) : TryGetLastNonIterator(source, out found); } private static TSource? TryGetLastNonIterator<TSource>(IEnumerable<TSource> source, out bool found) { if (source is IList<TSource> list) { int count = list.Count; if (count > 0) { found = true; return list[count - 1]; } } else { using IEnumerator<TSource> e = source.GetEnumerator(); if (e.MoveNext()) { TSource result; do { result = e.Current; } while (e.MoveNext()); found = true; return result; } } found = false; return default; } private static TSource? TryGetLast<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate, out bool found) { if (source is null) { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source); } if (predicate is null) { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.predicate); } if (source is OrderedIterator<TSource> ordered) { return ordered.TryGetLast(predicate, out found); } if (source is IList<TSource> list) { for (int i = list.Count - 1; i >= 0; --i) { TSource result = list[i]; if (predicate(result)) { found = true; return result; } } } else { using IEnumerator<TSource> e = source.GetEnumerator(); while (e.MoveNext()) { TSource result = e.Current; if (predicate(result)) { while (e.MoveNext()) { TSource element = e.Current; if (predicate(element)) { result = element; } } found = true; return result; } } } found = false; return default; } } }