/// <summary>
        /// Returns the maximal element of a sequence based on a specified projection and comparer for projected
        /// values.
        /// </summary>
        /// <remarks>
        /// If more than one element has the maximal projected value, the first one encountered will be returned. This
        /// overload uses the default comparer for the projected type. This operator uses immediate execution, but only
        /// buffers a single result (the current maximal element).
        /// </remarks>
        /// <typeparam name="TSource">The type of source sequence.</typeparam>
        /// <typeparam name="TKey">The type of projected element.</typeparam>
        /// <param name="source">The source sequence.</param>
        /// <param name="selector">A transform function to apply to each element.</param>
        /// <param name="comparer">A comparer used to compare projected values.</param>
        /// <returns>The maximal element, according to the projection.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="source"/> is <see langword="null"/>.</exception>
        /// <exception cref="ArgumentNullException"><paramref name="selector"/> is <see langword="null"/>.</exception>
        /// <exception cref="ArgumentNullException"><paramref name="comparer"/> is <see langword="null"/>.</exception>
        /// <exception cref="InvalidOperationException"><paramref name="source"/> is empty.</exception>
        public static TSource MaxBy <TSource, TKey>(
            this IEnumerable <TSource> source, Func <TSource, TKey> selector, IComparer <TKey> comparer)
        {
            source.AssertNotNull("source");
            selector.AssertNotNull("selector");
            comparer.AssertNotNull("comparer");

            using (IEnumerator <TSource> sourceIterator = source.GetEnumerator())
            {
                if (!sourceIterator.MoveNext())
                {
                    throw new InvalidOperationException("The sequence is empty.");
                }

                var max    = sourceIterator.Current;
                var maxKey = selector(max);

                while (sourceIterator.MoveNext())
                {
                    var candidate          = sourceIterator.Current;
                    var candidateProjected = selector(candidate);

                    if (comparer.Compare(candidateProjected, maxKey) > 0)
                    {
                        max    = candidate;
                        maxKey = candidateProjected;
                    }
                }

                return(max);
            }
        }